@rokkit/graph 1.7.0 → 1.8.1
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.
- package/README.md +67 -1
- package/dist/Graph.svelte +234 -259
- package/dist/Graph.svelte.d.ts +1 -1
- package/dist/GraphLegend.svelte +81 -10
- package/dist/GraphLegend.svelte.d.ts +15 -0
- package/dist/GraphState.svelte.d.ts +168 -51
- package/dist/GraphState.svelte.js +406 -305
- package/dist/actions/canvas.d.ts +18 -0
- package/dist/actions/canvas.js +59 -0
- package/dist/actions/choices.d.ts +12 -0
- package/dist/actions/choices.js +23 -0
- package/dist/actions/interactions.d.ts +20 -0
- package/dist/actions/interactions.js +57 -0
- package/dist/actions/listen.d.ts +2 -0
- package/dist/actions/listen.js +10 -0
- package/dist/canvas/frame.d.ts +41 -0
- package/dist/canvas/frame.js +34 -0
- package/dist/controls/BundleControl.svelte +11 -10
- package/dist/controls/BundleControl.svelte.d.ts +0 -7
- package/dist/controls/DensityControl.svelte +17 -9
- package/dist/controls/DensityControl.svelte.d.ts +0 -8
- package/dist/controls/DepthControl.svelte +11 -4
- package/dist/controls/DepthControl.svelte.d.ts +0 -9
- package/dist/controls/DrillBar.svelte +63 -0
- package/dist/controls/DrillBar.svelte.d.ts +9 -0
- package/dist/controls/EdgeStyleControl.svelte +10 -10
- package/dist/controls/EdgeStyleControl.svelte.d.ts +0 -6
- package/dist/controls/HiddenControl.svelte +27 -0
- package/dist/controls/HiddenControl.svelte.d.ts +7 -0
- package/dist/controls/MeasureControl.svelte +39 -0
- package/dist/controls/MeasureControl.svelte.d.ts +12 -0
- package/dist/controls/ToggleControl.svelte +33 -0
- package/dist/controls/ToggleControl.svelte.d.ts +13 -0
- package/dist/controls/ViolationsControl.svelte +27 -0
- package/dist/controls/ViolationsControl.svelte.d.ts +7 -0
- package/dist/controls/ZoomControl.svelte +21 -18
- package/dist/controls/zoom.d.ts +3 -0
- package/dist/controls/zoom.js +6 -0
- package/dist/diagrams/ArcDiagram.svelte +116 -0
- package/dist/diagrams/ArcDiagram.svelte.d.ts +31 -0
- package/dist/diagrams/CallTree.svelte +17 -5
- package/dist/diagrams/CallTree.svelte.d.ts +5 -1
- package/dist/diagrams/DependencyDiagram.svelte +18 -6
- package/dist/diagrams/DependencyDiagram.svelte.d.ts +5 -1
- package/dist/diagrams/DependencyMatrix.svelte +156 -0
- package/dist/diagrams/DependencyMatrix.svelte.d.ts +34 -0
- package/dist/diagrams/ErDiagram.svelte +18 -6
- package/dist/diagrams/ErDiagram.svelte.d.ts +5 -1
- package/dist/diagrams/LayersDiagram.svelte +124 -0
- package/dist/diagrams/LayersDiagram.svelte.d.ts +30 -0
- package/dist/diagrams/Neighborhood.svelte +26 -6
- package/dist/diagrams/Neighborhood.svelte.d.ts +11 -1
- package/dist/diagrams/PolymetricTree.svelte +116 -0
- package/dist/diagrams/PolymetricTree.svelte.d.ts +28 -0
- package/dist/diagrams/StructureDiagram.svelte +38 -8
- package/dist/diagrams/StructureDiagram.svelte.d.ts +9 -1
- package/dist/diagrams/Sunburst.svelte +44 -8
- package/dist/diagrams/Sunburst.svelte.d.ts +12 -2
- package/dist/diagrams/Treemap.svelte +44 -8
- package/dist/diagrams/Treemap.svelte.d.ts +12 -2
- package/dist/index.d.ts +13 -3
- package/dist/index.js +11 -2
- package/dist/layout/arcs.d.ts +6 -0
- package/dist/layout/arcs.js +141 -0
- package/dist/layout/cards.js +9 -2
- package/dist/layout/edges.d.ts +13 -1
- package/dist/layout/edges.js +35 -0
- package/dist/layout/extent.d.ts +17 -0
- package/dist/layout/extent.js +27 -0
- package/dist/layout/flow.js +3 -1
- package/dist/layout/index.d.ts +4 -1
- package/dist/layout/index.js +17 -2
- package/dist/layout/layers.d.ts +6 -0
- package/dist/layout/layers.js +180 -0
- package/dist/layout/matrix.d.ts +50 -0
- package/dist/layout/matrix.js +110 -0
- package/dist/layout/neighborhood.js +16 -7
- package/dist/layout/options.d.ts +1 -1
- package/dist/layout/options.js +16 -3
- package/dist/layout/percentile.d.ts +8 -0
- package/dist/layout/percentile.js +13 -0
- package/dist/layout/polymetric.d.ts +3 -0
- package/dist/layout/polymetric.js +221 -0
- package/dist/layout/radial.js +3 -1
- package/dist/layout/structure.js +7 -1
- package/dist/layout/sunburst.js +11 -4
- package/dist/layout/types.d.ts +83 -0
- package/dist/layout/world.js +11 -4
- package/dist/messages.d.ts +14 -0
- package/dist/messages.js +17 -0
- package/dist/model/condense.d.ts +8 -0
- package/dist/model/condense.js +114 -0
- package/dist/model/entities.d.ts +12 -0
- package/dist/model/entities.js +12 -0
- package/dist/model/normalize.d.ts +2 -6
- package/dist/model/normalize.js +83 -5
- package/dist/model/relationships.d.ts +30 -0
- package/dist/model/relationships.js +51 -0
- package/dist/model/share.d.ts +9 -0
- package/dist/model/share.js +43 -0
- package/dist/model/tree.d.ts +7 -1
- package/dist/model/tree.js +11 -4
- package/dist/preset.d.ts +18 -0
- package/dist/preset.js +34 -3
- package/dist/schema/EntitiesView.svelte +8 -6
- package/dist/schema/EntityView.svelte +13 -10
- package/dist/state/GraphConfig.svelte.d.ts +124 -0
- package/dist/state/GraphConfig.svelte.js +253 -0
- package/dist/state/GraphDrill.svelte.d.ts +52 -0
- package/dist/state/GraphDrill.svelte.js +115 -0
- package/dist/state/GraphGroups.svelte.d.ts +35 -0
- package/dist/state/GraphGroups.svelte.js +73 -0
- package/dist/state/GraphSelection.svelte.d.ts +53 -0
- package/dist/state/GraphSelection.svelte.js +94 -0
- package/dist/state/intents.d.ts +33 -0
- package/dist/state/intents.js +30 -0
- package/dist/state/text.d.ts +28 -0
- package/dist/state/text.js +56 -0
- package/dist/types.d.ts +92 -1
- package/package.json +5 -4
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dependency structure matrix: every node a row and a column, a cell where the row
|
|
3
|
+
* depends on the column.
|
|
4
|
+
*
|
|
5
|
+
* Providers come first, so a layered codebase is lower-triangular and a mark ABOVE the
|
|
6
|
+
* diagonal is a dependency against the grain — a cycle, or a layer reaching up. Groups sit
|
|
7
|
+
* on the diagonal as outlined blocks, so a cross-module violation is a mark outside its
|
|
8
|
+
* block. It stays readable at sizes where a node-link drawing is a hairball, which is the
|
|
9
|
+
* reason to reach for it.
|
|
10
|
+
*
|
|
11
|
+
* Share a `state` with a `DependencyDiagram` beside it and a row click selects the same
|
|
12
|
+
* node in both.
|
|
13
|
+
*/
|
|
14
|
+
import { GraphState } from '../GraphState.svelte.js';
|
|
15
|
+
import type { NodeAxis } from '../layout/types.js';
|
|
16
|
+
import type { GraphFields } from '../types.js';
|
|
17
|
+
type Props = {
|
|
18
|
+
/** Share one state with another view. The caller owns it; this component never updates it. */
|
|
19
|
+
state?: GraphState;
|
|
20
|
+
nodes?: unknown[];
|
|
21
|
+
edges?: unknown[];
|
|
22
|
+
fields?: GraphFields;
|
|
23
|
+
/** Keep each group contiguous and outline it on the diagonal. `null` for one flat order. */
|
|
24
|
+
groupBy?: NodeAxis | null;
|
|
25
|
+
/** Cell size in pixels. */
|
|
26
|
+
cell?: number;
|
|
27
|
+
value?: string | null;
|
|
28
|
+
label?: string;
|
|
29
|
+
onselect?: (id: string | null) => void;
|
|
30
|
+
class?: string;
|
|
31
|
+
};
|
|
32
|
+
declare const DependencyMatrix: import("svelte").Component<Props, {}, "value">;
|
|
33
|
+
type DependencyMatrix = ReturnType<typeof DependencyMatrix>;
|
|
34
|
+
export default DependencyMatrix;
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
import GraphLegend from '../GraphLegend.svelte'
|
|
15
15
|
import DiagramFrame from './DiagramFrame.svelte'
|
|
16
16
|
import DensityControl from '../controls/DensityControl.svelte'
|
|
17
|
+
import DrillBar from '../controls/DrillBar.svelte'
|
|
17
18
|
import EdgeStyleControl from '../controls/EdgeStyleControl.svelte'
|
|
18
19
|
import ZoomControl from '../controls/ZoomControl.svelte'
|
|
19
20
|
import { GraphState } from '../GraphState.svelte.js'
|
|
20
21
|
import type { Density, EdgeStyle } from '../layout/types.js'
|
|
21
|
-
import type { GraphFields } from '../types.js'
|
|
22
|
+
import type { GraphFields, GraphNode } from '../types.js'
|
|
22
23
|
import type { GraphPreset } from '../preset.js'
|
|
23
24
|
|
|
24
25
|
type Props = {
|
|
@@ -45,6 +46,10 @@
|
|
|
45
46
|
arrows?: boolean
|
|
46
47
|
label?: string
|
|
47
48
|
onselect?: (id: string | null) => void
|
|
49
|
+
/** The reader expanded a group node (#166) — with its members in `nodes`, they appear at once. */
|
|
50
|
+
onexpand?: (id: string, node: GraphNode) => void
|
|
51
|
+
/** The reader collapsed a group back into one node. */
|
|
52
|
+
oncollapse?: (id: string, node: GraphNode) => void
|
|
48
53
|
class?: string
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -64,6 +69,8 @@
|
|
|
64
69
|
arrows = true,
|
|
65
70
|
label = undefined,
|
|
66
71
|
onselect = undefined,
|
|
72
|
+
onexpand = undefined,
|
|
73
|
+
oncollapse = undefined,
|
|
67
74
|
class: className = ''
|
|
68
75
|
}: Props = $props()
|
|
69
76
|
|
|
@@ -81,7 +88,9 @@
|
|
|
81
88
|
preset,
|
|
82
89
|
mode,
|
|
83
90
|
label,
|
|
84
|
-
onselect
|
|
91
|
+
onselect,
|
|
92
|
+
onexpand,
|
|
93
|
+
oncollapse
|
|
85
94
|
})
|
|
86
95
|
|
|
87
96
|
// svelte-ignore state_referenced_locally
|
|
@@ -108,9 +117,12 @@
|
|
|
108
117
|
inside is always defined, so the frame would render an empty control bar over
|
|
109
118
|
every diagram that asked for none. -->
|
|
110
119
|
{#snippet controlBar()}
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
<DrillBar state={graph} />
|
|
121
|
+
{#if controls}
|
|
122
|
+
<DensityControl {density} onchange={(v) => (density = v)} />
|
|
123
|
+
<EdgeStyleControl {edgeStyle} onchange={(v) => (edgeStyle = v)} />
|
|
124
|
+
<ZoomControl {zoom} onchange={(v) => (zoom = v)} />
|
|
125
|
+
{/if}
|
|
114
126
|
{/snippet}
|
|
115
127
|
|
|
116
128
|
{#snippet legendBar()}
|
|
@@ -119,7 +131,7 @@
|
|
|
119
131
|
|
|
120
132
|
<DiagramFrame
|
|
121
133
|
class={className}
|
|
122
|
-
overlay={controls ? controlBar : undefined}
|
|
134
|
+
overlay={controls || graph.showsDrillBar ? controlBar : undefined}
|
|
123
135
|
footer={legend ? legendBar : undefined}
|
|
124
136
|
>
|
|
125
137
|
{#snippet canvas()}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GraphState } from '../GraphState.svelte.js';
|
|
2
2
|
import type { Density, EdgeStyle } from '../layout/types.js';
|
|
3
|
-
import type { GraphFields } from '../types.js';
|
|
3
|
+
import type { GraphFields, GraphNode } from '../types.js';
|
|
4
4
|
import type { GraphPreset } from '../preset.js';
|
|
5
5
|
type Props = {
|
|
6
6
|
/**
|
|
@@ -26,6 +26,10 @@ type Props = {
|
|
|
26
26
|
arrows?: boolean;
|
|
27
27
|
label?: string;
|
|
28
28
|
onselect?: (id: string | null) => void;
|
|
29
|
+
/** The reader expanded a group node (#166) — with its members in `nodes`, they appear at once. */
|
|
30
|
+
onexpand?: (id: string, node: GraphNode) => void;
|
|
31
|
+
/** The reader collapsed a group back into one node. */
|
|
32
|
+
oncollapse?: (id: string, node: GraphNode) => void;
|
|
29
33
|
class?: string;
|
|
30
34
|
};
|
|
31
35
|
declare const ErDiagram: import("svelte").Component<Props, {}, "value" | "density" | "edgeStyle">;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The intended layers, top to bottom, with every dependency between them (#167).
|
|
4
|
+
*
|
|
5
|
+
* Arrows should only point DOWN. The ones that climb are layer violations and are the output
|
|
6
|
+
* of the view — `ViolationsControl` shows only those. The host assigns each node its `layer`
|
|
7
|
+
* (it knows the architecture it intends); rokkit computes no depth, and marks each edge
|
|
8
|
+
* `down` / `skip` / `up` / `level` from those layers unless the host already said.
|
|
9
|
+
*/
|
|
10
|
+
import Graph from '../Graph.svelte'
|
|
11
|
+
import GraphLegend from '../GraphLegend.svelte'
|
|
12
|
+
import DiagramFrame from './DiagramFrame.svelte'
|
|
13
|
+
import DensityControl from '../controls/DensityControl.svelte'
|
|
14
|
+
import DrillBar from '../controls/DrillBar.svelte'
|
|
15
|
+
import ViolationsControl from '../controls/ViolationsControl.svelte'
|
|
16
|
+
import ZoomControl from '../controls/ZoomControl.svelte'
|
|
17
|
+
import { GraphState } from '../GraphState.svelte.js'
|
|
18
|
+
import type { Density } from '../layout/types.js'
|
|
19
|
+
import type { GraphFields, GraphNode } from '../types.js'
|
|
20
|
+
import type { GraphPreset } from '../preset.js'
|
|
21
|
+
|
|
22
|
+
type Props = {
|
|
23
|
+
/** Share one state with another view — see `DependencyDiagram`. */
|
|
24
|
+
state?: GraphState
|
|
25
|
+
nodes?: unknown[]
|
|
26
|
+
edges?: unknown[]
|
|
27
|
+
fields?: GraphFields
|
|
28
|
+
density?: Density
|
|
29
|
+
/** Every edge, or only the ones that climb. Bindable — the control moves it. */
|
|
30
|
+
showEdges?: 'all' | 'violations'
|
|
31
|
+
/** Band names by layer index; an unnamed layer reads "Layer N". */
|
|
32
|
+
layerLabels?: string[]
|
|
33
|
+
controls?: boolean
|
|
34
|
+
legend?: boolean
|
|
35
|
+
value?: string | null
|
|
36
|
+
preset?: GraphPreset
|
|
37
|
+
mode?: 'light' | 'dark'
|
|
38
|
+
arrows?: boolean
|
|
39
|
+
label?: string
|
|
40
|
+
onselect?: (id: string | null) => void
|
|
41
|
+
onexpand?: (id: string, node: GraphNode) => void
|
|
42
|
+
oncollapse?: (id: string, node: GraphNode) => void
|
|
43
|
+
class?: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
state: provided,
|
|
48
|
+
nodes = [],
|
|
49
|
+
edges = [],
|
|
50
|
+
fields = {},
|
|
51
|
+
density = $bindable('names'),
|
|
52
|
+
showEdges = $bindable('all'),
|
|
53
|
+
layerLabels = undefined,
|
|
54
|
+
controls = false,
|
|
55
|
+
legend = false,
|
|
56
|
+
value = $bindable(undefined),
|
|
57
|
+
preset = undefined,
|
|
58
|
+
mode = 'light',
|
|
59
|
+
arrows = true,
|
|
60
|
+
label = undefined,
|
|
61
|
+
onselect = undefined,
|
|
62
|
+
onexpand = undefined,
|
|
63
|
+
oncollapse = undefined,
|
|
64
|
+
class: className = ''
|
|
65
|
+
}: Props = $props()
|
|
66
|
+
|
|
67
|
+
let zoom = $state(1)
|
|
68
|
+
|
|
69
|
+
const config = () => ({
|
|
70
|
+
nodes,
|
|
71
|
+
edges,
|
|
72
|
+
fields,
|
|
73
|
+
layout: 'layers',
|
|
74
|
+
density,
|
|
75
|
+
showEdges,
|
|
76
|
+
layerLabels,
|
|
77
|
+
value,
|
|
78
|
+
preset,
|
|
79
|
+
mode,
|
|
80
|
+
label,
|
|
81
|
+
onselect,
|
|
82
|
+
onexpand,
|
|
83
|
+
oncollapse
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// svelte-ignore state_referenced_locally
|
|
87
|
+
const graph = provided ?? new GraphState(config())
|
|
88
|
+
|
|
89
|
+
$effect(() => {
|
|
90
|
+
if (!provided) {
|
|
91
|
+
graph.update(config())
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
// A supplied state is the caller's — see DependencyDiagram. Only this component's own
|
|
95
|
+
// options are merged in.
|
|
96
|
+
const { nodes: _n, edges: _e, fields: _f, preset: _p, mode: _m, value: _v, ...mine } =
|
|
97
|
+
config()
|
|
98
|
+
graph.apply(mine)
|
|
99
|
+
})
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<!-- Snippets are declared OUTSIDE the frame and passed conditionally — see DependencyDiagram. -->
|
|
103
|
+
{#snippet controlBar()}
|
|
104
|
+
<DrillBar state={graph} />
|
|
105
|
+
{#if controls}
|
|
106
|
+
<ViolationsControl {showEdges} onchange={(v) => (showEdges = v)} />
|
|
107
|
+
<DensityControl {density} onchange={(v) => (density = v)} />
|
|
108
|
+
<ZoomControl {zoom} onchange={(v) => (zoom = v)} />
|
|
109
|
+
{/if}
|
|
110
|
+
{/snippet}
|
|
111
|
+
|
|
112
|
+
{#snippet legendBar()}
|
|
113
|
+
<GraphLegend state={graph} relations />
|
|
114
|
+
{/snippet}
|
|
115
|
+
|
|
116
|
+
<DiagramFrame
|
|
117
|
+
class={className}
|
|
118
|
+
overlay={controls || graph.showsDrillBar ? controlBar : undefined}
|
|
119
|
+
footer={legend ? legendBar : undefined}
|
|
120
|
+
>
|
|
121
|
+
{#snippet canvas()}
|
|
122
|
+
<Graph state={graph} bind:zoom {arrows} />
|
|
123
|
+
{/snippet}
|
|
124
|
+
</DiagramFrame>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GraphState } from '../GraphState.svelte.js';
|
|
2
|
+
import type { Density } from '../layout/types.js';
|
|
3
|
+
import type { GraphFields, GraphNode } from '../types.js';
|
|
4
|
+
import type { GraphPreset } from '../preset.js';
|
|
5
|
+
type Props = {
|
|
6
|
+
/** Share one state with another view — see `DependencyDiagram`. */
|
|
7
|
+
state?: GraphState;
|
|
8
|
+
nodes?: unknown[];
|
|
9
|
+
edges?: unknown[];
|
|
10
|
+
fields?: GraphFields;
|
|
11
|
+
density?: Density;
|
|
12
|
+
/** Every edge, or only the ones that climb. Bindable — the control moves it. */
|
|
13
|
+
showEdges?: 'all' | 'violations';
|
|
14
|
+
/** Band names by layer index; an unnamed layer reads "Layer N". */
|
|
15
|
+
layerLabels?: string[];
|
|
16
|
+
controls?: boolean;
|
|
17
|
+
legend?: boolean;
|
|
18
|
+
value?: string | null;
|
|
19
|
+
preset?: GraphPreset;
|
|
20
|
+
mode?: 'light' | 'dark';
|
|
21
|
+
arrows?: boolean;
|
|
22
|
+
label?: string;
|
|
23
|
+
onselect?: (id: string | null) => void;
|
|
24
|
+
onexpand?: (id: string, node: GraphNode) => void;
|
|
25
|
+
oncollapse?: (id: string, node: GraphNode) => void;
|
|
26
|
+
class?: string;
|
|
27
|
+
};
|
|
28
|
+
declare const LayersDiagram: import("svelte").Component<Props, {}, "value" | "density" | "showEdges">;
|
|
29
|
+
type LayersDiagram = ReturnType<typeof LayersDiagram>;
|
|
30
|
+
export default LayersDiagram;
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
import GraphLegend from '../GraphLegend.svelte'
|
|
13
13
|
import DiagramFrame from './DiagramFrame.svelte'
|
|
14
14
|
import DepthControl from '../controls/DepthControl.svelte'
|
|
15
|
+
import DrillBar from '../controls/DrillBar.svelte'
|
|
15
16
|
import EdgeStyleControl from '../controls/EdgeStyleControl.svelte'
|
|
16
17
|
import ZoomControl from '../controls/ZoomControl.svelte'
|
|
17
18
|
import { GraphState } from '../GraphState.svelte.js'
|
|
18
19
|
import type { EdgeStyle } from '../layout/types.js'
|
|
19
|
-
import type { GraphFields } from '../types.js'
|
|
20
|
+
import type { GraphFields, GraphNode } from '../types.js'
|
|
20
21
|
import type { GraphPreset } from '../preset.js'
|
|
21
22
|
|
|
22
23
|
type Props = {
|
|
@@ -34,6 +35,12 @@
|
|
|
34
35
|
/** How many hops out. One answers "what touches this"; two, "what does this reach". */
|
|
35
36
|
depth?: number
|
|
36
37
|
edgeStyle?: EdgeStyle
|
|
38
|
+
/**
|
|
39
|
+
* Mark each card with its group's colour (#172). On by default, as in `ErDiagram`: a
|
|
40
|
+
* neighbourhood has no group boxes either, so without it a table's schema is visible at
|
|
41
|
+
* the root and invisible one click later.
|
|
42
|
+
*/
|
|
43
|
+
groupTint?: boolean
|
|
37
44
|
controls?: boolean
|
|
38
45
|
maxDepth?: number
|
|
39
46
|
legend?: boolean
|
|
@@ -43,6 +50,10 @@
|
|
|
43
50
|
arrows?: boolean
|
|
44
51
|
label?: string
|
|
45
52
|
onselect?: (id: string | null) => void
|
|
53
|
+
/** The reader expanded a group node (#166) — with its members in `nodes`, they appear at once. */
|
|
54
|
+
onexpand?: (id: string, node: GraphNode) => void
|
|
55
|
+
/** The reader collapsed a group back into one node. */
|
|
56
|
+
oncollapse?: (id: string, node: GraphNode) => void
|
|
46
57
|
class?: string
|
|
47
58
|
}
|
|
48
59
|
|
|
@@ -54,6 +65,7 @@
|
|
|
54
65
|
focus = $bindable(null),
|
|
55
66
|
depth = $bindable(1),
|
|
56
67
|
edgeStyle = $bindable('curved'),
|
|
68
|
+
groupTint = true,
|
|
57
69
|
controls = false,
|
|
58
70
|
maxDepth = 3,
|
|
59
71
|
legend = false,
|
|
@@ -63,6 +75,8 @@
|
|
|
63
75
|
arrows = true,
|
|
64
76
|
label = undefined,
|
|
65
77
|
onselect = undefined,
|
|
78
|
+
onexpand = undefined,
|
|
79
|
+
oncollapse = undefined,
|
|
66
80
|
class: className = ''
|
|
67
81
|
}: Props = $props()
|
|
68
82
|
|
|
@@ -76,11 +90,14 @@
|
|
|
76
90
|
focus,
|
|
77
91
|
depth,
|
|
78
92
|
edgeStyle,
|
|
93
|
+
groupTint,
|
|
79
94
|
value,
|
|
80
95
|
preset,
|
|
81
96
|
mode,
|
|
82
97
|
label,
|
|
83
|
-
onselect
|
|
98
|
+
onselect,
|
|
99
|
+
onexpand,
|
|
100
|
+
oncollapse
|
|
84
101
|
})
|
|
85
102
|
|
|
86
103
|
// svelte-ignore state_referenced_locally
|
|
@@ -107,9 +124,12 @@
|
|
|
107
124
|
inside is always defined, so the frame would render an empty control bar over
|
|
108
125
|
every diagram that asked for none. -->
|
|
109
126
|
{#snippet controlBar()}
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
<DrillBar state={graph} />
|
|
128
|
+
{#if controls}
|
|
129
|
+
<DepthControl levels={depth} max={maxDepth} onchange={(v) => (depth = v)} />
|
|
130
|
+
<EdgeStyleControl {edgeStyle} onchange={(v) => (edgeStyle = v)} />
|
|
131
|
+
<ZoomControl {zoom} onchange={(v) => (zoom = v)} />
|
|
132
|
+
{/if}
|
|
113
133
|
{/snippet}
|
|
114
134
|
|
|
115
135
|
{#snippet legendBar()}
|
|
@@ -118,7 +138,7 @@
|
|
|
118
138
|
|
|
119
139
|
<DiagramFrame
|
|
120
140
|
class={className}
|
|
121
|
-
overlay={controls ? controlBar : undefined}
|
|
141
|
+
overlay={controls || graph.showsDrillBar ? controlBar : undefined}
|
|
122
142
|
footer={legend ? legendBar : undefined}
|
|
123
143
|
>
|
|
124
144
|
{#snippet canvas()}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GraphState } from '../GraphState.svelte.js';
|
|
2
2
|
import type { EdgeStyle } from '../layout/types.js';
|
|
3
|
-
import type { GraphFields } from '../types.js';
|
|
3
|
+
import type { GraphFields, GraphNode } from '../types.js';
|
|
4
4
|
import type { GraphPreset } from '../preset.js';
|
|
5
5
|
type Props = {
|
|
6
6
|
/**
|
|
@@ -17,6 +17,12 @@ type Props = {
|
|
|
17
17
|
/** How many hops out. One answers "what touches this"; two, "what does this reach". */
|
|
18
18
|
depth?: number;
|
|
19
19
|
edgeStyle?: EdgeStyle;
|
|
20
|
+
/**
|
|
21
|
+
* Mark each card with its group's colour (#172). On by default, as in `ErDiagram`: a
|
|
22
|
+
* neighbourhood has no group boxes either, so without it a table's schema is visible at
|
|
23
|
+
* the root and invisible one click later.
|
|
24
|
+
*/
|
|
25
|
+
groupTint?: boolean;
|
|
20
26
|
controls?: boolean;
|
|
21
27
|
maxDepth?: number;
|
|
22
28
|
legend?: boolean;
|
|
@@ -26,6 +32,10 @@ type Props = {
|
|
|
26
32
|
arrows?: boolean;
|
|
27
33
|
label?: string;
|
|
28
34
|
onselect?: (id: string | null) => void;
|
|
35
|
+
/** The reader expanded a group node (#166) — with its members in `nodes`, they appear at once. */
|
|
36
|
+
onexpand?: (id: string, node: GraphNode) => void;
|
|
37
|
+
/** The reader collapsed a group back into one node. */
|
|
38
|
+
oncollapse?: (id: string, node: GraphNode) => void;
|
|
29
39
|
class?: string;
|
|
30
40
|
};
|
|
31
41
|
declare const Neighborhood: import("svelte").Component<Props, {}, "focus" | "value" | "edgeStyle" | "depth">;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Lanza & Marinescu's System Complexity view (#168): the containment tree, each file a box
|
|
4
|
+
* whose width, height and shade show three measures at once.
|
|
5
|
+
*
|
|
6
|
+
* `Treemap` encodes ONE measure as area; this encodes three, and the three-at-once is the
|
|
7
|
+
* point — a narrow, tall, dark box reads differently from a wide, short, pale one. Each
|
|
8
|
+
* channel is a prop and a picker, and the legend names them by default, because three
|
|
9
|
+
* encodings are unreadable without a key.
|
|
10
|
+
*/
|
|
11
|
+
import Graph from '../Graph.svelte'
|
|
12
|
+
import GraphLegend from '../GraphLegend.svelte'
|
|
13
|
+
import DiagramFrame from './DiagramFrame.svelte'
|
|
14
|
+
import DrillBar from '../controls/DrillBar.svelte'
|
|
15
|
+
import MeasureControl from '../controls/MeasureControl.svelte'
|
|
16
|
+
import ZoomControl from '../controls/ZoomControl.svelte'
|
|
17
|
+
import { GraphState } from '../GraphState.svelte.js'
|
|
18
|
+
import type { GraphFields } from '../types.js'
|
|
19
|
+
import type { GraphPreset } from '../preset.js'
|
|
20
|
+
|
|
21
|
+
type Props = {
|
|
22
|
+
/** Share one state with another view — see `DependencyDiagram`. */
|
|
23
|
+
state?: GraphState
|
|
24
|
+
nodes?: unknown[]
|
|
25
|
+
edges?: unknown[]
|
|
26
|
+
fields?: GraphFields
|
|
27
|
+
/** What box WIDTH encodes: a `measures` key, `weight`, or `degree`. Bindable. */
|
|
28
|
+
widthBy?: string
|
|
29
|
+
/** What box HEIGHT encodes. Bindable. */
|
|
30
|
+
heightBy?: string
|
|
31
|
+
/** What box SHADE encodes; omit for no colour channel. Bindable. */
|
|
32
|
+
colorBy?: string
|
|
33
|
+
controls?: boolean
|
|
34
|
+
/** On by default: three encodings are unreadable without a key. */
|
|
35
|
+
legend?: boolean
|
|
36
|
+
value?: string | null
|
|
37
|
+
preset?: GraphPreset
|
|
38
|
+
mode?: 'light' | 'dark'
|
|
39
|
+
label?: string
|
|
40
|
+
onselect?: (id: string | null) => void
|
|
41
|
+
class?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let {
|
|
45
|
+
state: provided,
|
|
46
|
+
nodes = [],
|
|
47
|
+
edges = [],
|
|
48
|
+
fields = {},
|
|
49
|
+
widthBy = $bindable('weight'),
|
|
50
|
+
heightBy = $bindable('weight'),
|
|
51
|
+
colorBy = $bindable(undefined),
|
|
52
|
+
controls = false,
|
|
53
|
+
legend = true,
|
|
54
|
+
value = $bindable(undefined),
|
|
55
|
+
preset = undefined,
|
|
56
|
+
mode = 'light',
|
|
57
|
+
label = undefined,
|
|
58
|
+
onselect = undefined,
|
|
59
|
+
class: className = ''
|
|
60
|
+
}: Props = $props()
|
|
61
|
+
|
|
62
|
+
let zoom = $state(1)
|
|
63
|
+
|
|
64
|
+
const config = () => ({
|
|
65
|
+
nodes,
|
|
66
|
+
edges,
|
|
67
|
+
fields,
|
|
68
|
+
layout: 'polymetric',
|
|
69
|
+
widthBy,
|
|
70
|
+
heightBy,
|
|
71
|
+
colorBy,
|
|
72
|
+
value,
|
|
73
|
+
preset,
|
|
74
|
+
mode,
|
|
75
|
+
label,
|
|
76
|
+
onselect
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// svelte-ignore state_referenced_locally
|
|
80
|
+
const graph = provided ?? new GraphState(config())
|
|
81
|
+
|
|
82
|
+
$effect(() => {
|
|
83
|
+
if (!provided) {
|
|
84
|
+
graph.update(config())
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
// A supplied state is the caller's — see DependencyDiagram.
|
|
88
|
+
const { nodes: _n, edges: _e, fields: _f, preset: _p, mode: _m, value: _v, ...mine } =
|
|
89
|
+
config()
|
|
90
|
+
graph.apply(mine)
|
|
91
|
+
})
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
{#snippet controlBar()}
|
|
95
|
+
<DrillBar state={graph} />
|
|
96
|
+
{#if controls}
|
|
97
|
+
<MeasureControl channel="width" value={widthBy} options={graph.measureKeys} onchange={(v) => (widthBy = v ?? 'weight')} />
|
|
98
|
+
<MeasureControl channel="height" value={heightBy} options={graph.measureKeys} onchange={(v) => (heightBy = v ?? 'weight')} />
|
|
99
|
+
<MeasureControl channel="color" value={colorBy} options={graph.measureKeys} allowNone onchange={(v) => (colorBy = v)} />
|
|
100
|
+
<ZoomControl {zoom} onchange={(v) => (zoom = v)} />
|
|
101
|
+
{/if}
|
|
102
|
+
{/snippet}
|
|
103
|
+
|
|
104
|
+
{#snippet legendBar()}
|
|
105
|
+
<GraphLegend state={graph} channels />
|
|
106
|
+
{/snippet}
|
|
107
|
+
|
|
108
|
+
<DiagramFrame
|
|
109
|
+
class={className}
|
|
110
|
+
overlay={controls || graph.showsDrillBar ? controlBar : undefined}
|
|
111
|
+
footer={legend ? legendBar : undefined}
|
|
112
|
+
>
|
|
113
|
+
{#snippet canvas()}
|
|
114
|
+
<Graph state={graph} bind:zoom arrows={false} />
|
|
115
|
+
{/snippet}
|
|
116
|
+
</DiagramFrame>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { GraphState } from '../GraphState.svelte.js';
|
|
2
|
+
import type { GraphFields } from '../types.js';
|
|
3
|
+
import type { GraphPreset } from '../preset.js';
|
|
4
|
+
type Props = {
|
|
5
|
+
/** Share one state with another view — see `DependencyDiagram`. */
|
|
6
|
+
state?: GraphState;
|
|
7
|
+
nodes?: unknown[];
|
|
8
|
+
edges?: unknown[];
|
|
9
|
+
fields?: GraphFields;
|
|
10
|
+
/** What box WIDTH encodes: a `measures` key, `weight`, or `degree`. Bindable. */
|
|
11
|
+
widthBy?: string;
|
|
12
|
+
/** What box HEIGHT encodes. Bindable. */
|
|
13
|
+
heightBy?: string;
|
|
14
|
+
/** What box SHADE encodes; omit for no colour channel. Bindable. */
|
|
15
|
+
colorBy?: string;
|
|
16
|
+
controls?: boolean;
|
|
17
|
+
/** On by default: three encodings are unreadable without a key. */
|
|
18
|
+
legend?: boolean;
|
|
19
|
+
value?: string | null;
|
|
20
|
+
preset?: GraphPreset;
|
|
21
|
+
mode?: 'light' | 'dark';
|
|
22
|
+
label?: string;
|
|
23
|
+
onselect?: (id: string | null) => void;
|
|
24
|
+
class?: string;
|
|
25
|
+
};
|
|
26
|
+
declare const PolymetricTree: import("svelte").Component<Props, {}, "value" | "widthBy" | "heightBy" | "colorBy">;
|
|
27
|
+
type PolymetricTree = ReturnType<typeof PolymetricTree>;
|
|
28
|
+
export default PolymetricTree;
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
import GraphLegend from '../GraphLegend.svelte'
|
|
16
16
|
import DiagramFrame from './DiagramFrame.svelte'
|
|
17
17
|
import DepthControl from '../controls/DepthControl.svelte'
|
|
18
|
+
import DrillBar from '../controls/DrillBar.svelte'
|
|
18
19
|
import BundleControl from '../controls/BundleControl.svelte'
|
|
19
20
|
import ZoomControl from '../controls/ZoomControl.svelte'
|
|
20
21
|
import { GraphState } from '../GraphState.svelte.js'
|
|
21
|
-
import type { GraphFields } from '../types.js'
|
|
22
|
+
import type { GraphFields, GraphNode } from '../types.js'
|
|
22
23
|
import type { GraphPreset } from '../preset.js'
|
|
23
24
|
|
|
24
25
|
type Props = {
|
|
@@ -44,6 +45,14 @@
|
|
|
44
45
|
mode?: 'light' | 'dark'
|
|
45
46
|
label?: string
|
|
46
47
|
onselect?: (id: string | null) => void
|
|
48
|
+
/**
|
|
49
|
+
* The reader opened a box — `path` is the new `focusPath`, `node` the declared node there
|
|
50
|
+
* (null for a synthesised container). Return a promise while you load that level; the
|
|
51
|
+
* canvas shows it pending, and a rejection returns to the previous level.
|
|
52
|
+
*/
|
|
53
|
+
ondrill?: (path: string[], node: GraphNode | null) => void | Promise<void>
|
|
54
|
+
/** The reader climbed out; `path` is the new, shorter `focusPath`. */
|
|
55
|
+
ondrillup?: (path: string[]) => void | Promise<void>
|
|
47
56
|
class?: string
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -65,6 +74,8 @@
|
|
|
65
74
|
mode = 'light',
|
|
66
75
|
label = undefined,
|
|
67
76
|
onselect = undefined,
|
|
77
|
+
ondrill = undefined,
|
|
78
|
+
ondrillup = undefined,
|
|
68
79
|
class: className = ''
|
|
69
80
|
}: Props = $props()
|
|
70
81
|
|
|
@@ -84,7 +95,12 @@
|
|
|
84
95
|
preset,
|
|
85
96
|
mode,
|
|
86
97
|
label,
|
|
87
|
-
onselect
|
|
98
|
+
onselect,
|
|
99
|
+
ondrill,
|
|
100
|
+
ondrillup,
|
|
101
|
+
// Drilling moves focusPath inside the state; keep the bindable prop in step, or the next
|
|
102
|
+
// update() would put the old value back.
|
|
103
|
+
onfocuspath: (path: string[]) => (focusPath = path)
|
|
88
104
|
})
|
|
89
105
|
|
|
90
106
|
// svelte-ignore state_referenced_locally
|
|
@@ -101,8 +117,19 @@
|
|
|
101
117
|
// and are never reset here. What this component DOES own is the options its own
|
|
102
118
|
// controls drive — the layout above all, since choosing this component is choosing it.
|
|
103
119
|
// `apply` merges; `update` would revert everything it does not name.
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
// The drill path too: a caller's state holds where the reader drilled, and pushing this
|
|
121
|
+
// component's own focusPath prop back over it undid the drill on any prop change.
|
|
122
|
+
const {
|
|
123
|
+
nodes: _n,
|
|
124
|
+
edges: _e,
|
|
125
|
+
fields: _f,
|
|
126
|
+
preset: _p,
|
|
127
|
+
mode: _m,
|
|
128
|
+
value: _v,
|
|
129
|
+
focusPath: _fp,
|
|
130
|
+
onfocuspath: _sync,
|
|
131
|
+
...mine
|
|
132
|
+
} = config()
|
|
106
133
|
graph.apply(mine)
|
|
107
134
|
})
|
|
108
135
|
</script>
|
|
@@ -111,9 +138,12 @@
|
|
|
111
138
|
inside is always defined, so the frame would render an empty control bar over
|
|
112
139
|
every diagram that asked for none. -->
|
|
113
140
|
{#snippet controlBar()}
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
141
|
+
<DrillBar state={graph} />
|
|
142
|
+
{#if controls}
|
|
143
|
+
<DepthControl {levels} max={maxLevels} onchange={(v) => (levels = v)} />
|
|
144
|
+
<BundleControl {bundleTension} onchange={(v) => (bundleTension = v)} />
|
|
145
|
+
<ZoomControl {zoom} onchange={(v) => (zoom = v)} />
|
|
146
|
+
{/if}
|
|
117
147
|
{/snippet}
|
|
118
148
|
|
|
119
149
|
{#snippet legendBar()}
|
|
@@ -122,7 +152,7 @@
|
|
|
122
152
|
|
|
123
153
|
<DiagramFrame
|
|
124
154
|
class={className}
|
|
125
|
-
overlay={controls ? controlBar : undefined}
|
|
155
|
+
overlay={controls || graph.showsDrillBar ? controlBar : undefined}
|
|
126
156
|
footer={legend ? legendBar : undefined}
|
|
127
157
|
>
|
|
128
158
|
{#snippet canvas()}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphState } from '../GraphState.svelte.js';
|
|
2
|
-
import type { GraphFields } from '../types.js';
|
|
2
|
+
import type { GraphFields, GraphNode } from '../types.js';
|
|
3
3
|
import type { GraphPreset } from '../preset.js';
|
|
4
4
|
type Props = {
|
|
5
5
|
/** Share one state with views beside this one. See `ErDiagram` for the contract. */
|
|
@@ -24,6 +24,14 @@ type Props = {
|
|
|
24
24
|
mode?: 'light' | 'dark';
|
|
25
25
|
label?: string;
|
|
26
26
|
onselect?: (id: string | null) => void;
|
|
27
|
+
/**
|
|
28
|
+
* The reader opened a box — `path` is the new `focusPath`, `node` the declared node there
|
|
29
|
+
* (null for a synthesised container). Return a promise while you load that level; the
|
|
30
|
+
* canvas shows it pending, and a rejection returns to the previous level.
|
|
31
|
+
*/
|
|
32
|
+
ondrill?: (path: string[], node: GraphNode | null) => void | Promise<void>;
|
|
33
|
+
/** The reader climbed out; `path` is the new, shorter `focusPath`. */
|
|
34
|
+
ondrillup?: (path: string[]) => void | Promise<void>;
|
|
27
35
|
class?: string;
|
|
28
36
|
};
|
|
29
37
|
declare const StructureDiagram: import("svelte").Component<Props, {}, "value" | "focusPath" | "levels" | "bundleTension">;
|