@dxos/plugin-explorer 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a
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/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
- package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
- package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +4 -2
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/{chunk-JXYIG54N.mjs → chunk-4F6AT7RA.mjs} +4 -2
- package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
- package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
- package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +430 -506
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +4 -2
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
- package/dist/lib/neutral/hooks/index.mjs +64 -1
- package/dist/lib/neutral/hooks/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +1 -1
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +2 -2
- package/dist/lib/neutral/testing/index.mjs.map +2 -2
- package/dist/lib/neutral/translations.mjs +4 -1
- package/dist/lib/neutral/translations.mjs.map +2 -2
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +1 -7
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +1 -3
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
- package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/types.d.ts +1 -10
- package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
- package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
- package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/index.d.ts +3 -0
- package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/variants.d.ts +53 -0
- package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +1 -0
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +4 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/relations.d.ts +1 -2
- package/dist/types/src/testing/relations.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +6 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Graph.d.ts +6 -8
- package/dist/types/src/types/Graph.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -37
- package/src/ExplorerPlugin.tsx +2 -1
- package/src/capabilities/app-graph-builder.ts +40 -0
- package/src/capabilities/create-object.ts +3 -2
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/react-surface.tsx +14 -4
- package/src/components/Lattice/Lattice.tsx +1 -2
- package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
- package/src/components/Tree/Tree.stories.tsx +7 -2
- package/src/components/Tree/index.ts +3 -3
- package/src/components/Tree/types/tree.ts +6 -6
- package/src/components/Tree/types/types.ts +1 -11
- package/src/components/Visualization/Visualization.stories.tsx +104 -0
- package/src/components/Visualization/Visualization.tsx +209 -0
- package/src/components/Visualization/index.ts +6 -0
- package/src/components/Visualization/variants.ts +508 -0
- package/src/components/index.ts +1 -0
- package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
- package/src/containers/ExplorerArticle/ExplorerArticle.tsx +7 -8
- package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
- package/src/containers/NeighborhoodCompanion/index.ts +5 -0
- package/src/containers/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useNeighborhoodModel.ts +81 -0
- package/src/testing/relations.ts +1 -3
- package/src/translations.ts +3 -0
- package/src/types/Graph.ts +18 -20
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs +0 -460
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JXYIG54N.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
- package/dist/types/src/components/Tree/Tree.d.ts +0 -24
- package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
- package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
- package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
- package/src/components/Tree/Tree.tsx +0 -81
- package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
- package/src/components/Tree/layout/RadialTree.tsx +0 -242
- package/src/components/Tree/layout/TidyTree.tsx +0 -246
- package/src/components/Tree/layout/hierarchy.ts +0 -32
- package/src/components/Tree/layout/index.ts +0 -9
- package/src/components/Tree/layout/slots.ts +0 -19
- package/src/components/Tree/layout/useContainerSize.ts +0 -43
- package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
- package/src/containers/ExplorerArticle/variants.ts +0 -47
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Tree,
|
|
3
|
+
TreeNodeType,
|
|
4
|
+
TreeType,
|
|
2
5
|
treeTypeToTreeNode
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import {
|
|
5
|
-
createAdapter,
|
|
6
|
-
getNodeFillForObject
|
|
7
|
-
} from "../chunk-IKHJV3Q4.mjs";
|
|
6
|
+
} from "../chunk-EZ52JY7X.mjs";
|
|
8
7
|
import "../chunk-J5LGTIGS.mjs";
|
|
9
8
|
|
|
10
9
|
// src/components/Chart/Chart.tsx
|
|
11
10
|
import * as Plot from "@observablehq/plot";
|
|
12
11
|
import React, { useEffect } from "react";
|
|
13
12
|
import { useResizeDetector } from "react-resize-detector";
|
|
13
|
+
|
|
14
|
+
// src/util/node-color.ts
|
|
15
|
+
import { Obj } from "@dxos/echo";
|
|
16
|
+
import { getHashHue } from "@dxos/ui-theme";
|
|
17
|
+
var getNodeFillForTypename = (typename) => {
|
|
18
|
+
return `var(--color-${getHashHue(typename)}-400)`;
|
|
19
|
+
};
|
|
20
|
+
var getNodeFillForObject = (object) => {
|
|
21
|
+
return getNodeFillForTypename(object && Obj.getTypename(object));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/util/plot.ts
|
|
25
|
+
var createAdapter = (prop, accessor) => accessor ? {
|
|
26
|
+
transform: (values) => values.map((value) => accessor(value)[prop])
|
|
27
|
+
} : prop;
|
|
28
|
+
|
|
29
|
+
// src/components/Chart/Chart.tsx
|
|
14
30
|
var defaultOptions = {
|
|
15
31
|
r: 4,
|
|
16
32
|
stroke: "gray",
|
|
@@ -10934,7 +10950,7 @@ var assignRef = (ref, value) => {
|
|
|
10934
10950
|
// src/components/Graph/ForceGraph.tsx
|
|
10935
10951
|
import { Atom, useAtomValue } from "@effect-atom/atom-react";
|
|
10936
10952
|
import React4, { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
10937
|
-
import { Obj } from "@dxos/echo";
|
|
10953
|
+
import { Obj as Obj2 } from "@dxos/echo";
|
|
10938
10954
|
import { SelectionModel } from "@dxos/graph";
|
|
10939
10955
|
import { composable as composable2, composableProps as composableProps2 } from "@dxos/react-ui";
|
|
10940
10956
|
import { GraphForceProjector, SVG } from "@dxos/react-ui-graph";
|
|
@@ -11010,7 +11026,7 @@ var ForceGraph = composable2(({ model, selection: selectionProp, grid, drag, onI
|
|
|
11010
11026
|
const obj = node.data?.data.object;
|
|
11011
11027
|
return {
|
|
11012
11028
|
data: {
|
|
11013
|
-
color: getHashStyles(obj &&
|
|
11029
|
+
color: getHashStyles(obj && Obj2.getTypename(obj))?.hue
|
|
11014
11030
|
},
|
|
11015
11031
|
classes: {
|
|
11016
11032
|
"dx-selected": selection.contains(node.id)
|
|
@@ -11025,50 +11041,9 @@ var ForceGraph = composable2(({ model, selection: selectionProp, grid, drag, onI
|
|
|
11025
11041
|
|
|
11026
11042
|
// src/components/Lattice/Lattice.tsx
|
|
11027
11043
|
import { select } from "d3";
|
|
11028
|
-
import React5, { useEffect as
|
|
11029
|
-
import { Obj as
|
|
11030
|
-
|
|
11031
|
-
// src/components/Tree/layout/useContainerSize.ts
|
|
11032
|
-
import { useEffect as useEffect5, useState as useState3 } from "react";
|
|
11033
|
-
var useContainerSize = () => {
|
|
11034
|
-
const [el, setEl] = useState3(null);
|
|
11035
|
-
const [size, setSize] = useState3({
|
|
11036
|
-
width: 0,
|
|
11037
|
-
height: 0
|
|
11038
|
-
});
|
|
11039
|
-
useEffect5(() => {
|
|
11040
|
-
if (!el) {
|
|
11041
|
-
return;
|
|
11042
|
-
}
|
|
11043
|
-
const rect = el.getBoundingClientRect();
|
|
11044
|
-
setSize({
|
|
11045
|
-
width: rect.width,
|
|
11046
|
-
height: rect.height
|
|
11047
|
-
});
|
|
11048
|
-
const observer = new ResizeObserver((entries) => {
|
|
11049
|
-
const entry = entries[0];
|
|
11050
|
-
if (!entry) {
|
|
11051
|
-
return;
|
|
11052
|
-
}
|
|
11053
|
-
const { width, height } = entry.contentRect;
|
|
11054
|
-
setSize((prev) => prev.width === width && prev.height === height ? prev : {
|
|
11055
|
-
width,
|
|
11056
|
-
height
|
|
11057
|
-
});
|
|
11058
|
-
});
|
|
11059
|
-
observer.observe(el);
|
|
11060
|
-
return () => observer.disconnect();
|
|
11061
|
-
}, [
|
|
11062
|
-
el
|
|
11063
|
-
]);
|
|
11064
|
-
return {
|
|
11065
|
-
setRef: setEl,
|
|
11066
|
-
width: size.width,
|
|
11067
|
-
height: size.height
|
|
11068
|
-
};
|
|
11069
|
-
};
|
|
11070
|
-
|
|
11071
|
-
// src/components/Lattice/Lattice.tsx
|
|
11044
|
+
import React5, { useEffect as useEffect5, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
11045
|
+
import { Obj as Obj3 } from "@dxos/echo";
|
|
11046
|
+
import { useContainerSize } from "@dxos/react-ui-graph";
|
|
11072
11047
|
var TRANSITION_MS = 350;
|
|
11073
11048
|
var Lattice = ({ nodes, padding = 16, onNodeHover }) => {
|
|
11074
11049
|
const svgRef = useRef3(null);
|
|
@@ -11079,8 +11054,8 @@ var Lattice = ({ nodes, padding = 16, onNodeHover }) => {
|
|
|
11079
11054
|
if (!object) {
|
|
11080
11055
|
return void 0;
|
|
11081
11056
|
}
|
|
11082
|
-
const label = node.data?.label ??
|
|
11083
|
-
const typename =
|
|
11057
|
+
const label = node.data?.label ?? Obj3.getLabel(object) ?? node.id;
|
|
11058
|
+
const typename = Obj3.getTypename(object) ?? "(untyped)";
|
|
11084
11059
|
return {
|
|
11085
11060
|
id: node.id,
|
|
11086
11061
|
label,
|
|
@@ -11093,7 +11068,7 @@ var Lattice = ({ nodes, padding = 16, onNodeHover }) => {
|
|
|
11093
11068
|
]);
|
|
11094
11069
|
const handleHoverRef = useRef3(void 0);
|
|
11095
11070
|
handleHoverRef.current = onNodeHover;
|
|
11096
|
-
|
|
11071
|
+
useEffect5(() => {
|
|
11097
11072
|
if (!svgRef.current || !width || !height) {
|
|
11098
11073
|
return;
|
|
11099
11074
|
}
|
|
@@ -11167,501 +11142,450 @@ var renderLattice = (svgElement, cells, options) => {
|
|
|
11167
11142
|
}, event)).on("pointerleave", () => onNodeHover(null));
|
|
11168
11143
|
};
|
|
11169
11144
|
|
|
11170
|
-
// src/components/
|
|
11171
|
-
import
|
|
11145
|
+
// src/components/Visualization/Visualization.tsx
|
|
11146
|
+
import { createContext } from "@radix-ui/react-context";
|
|
11147
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
11148
|
+
import React6, { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef4, useState as useState3 } from "react";
|
|
11149
|
+
import { composableProps as composableProps3, slottable } from "@dxos/react-ui";
|
|
11150
|
+
import { GraphSwarmProjector as GraphSwarmProjector2, SVG as SVG2 } from "@dxos/react-ui-graph";
|
|
11172
11151
|
|
|
11173
|
-
// src/components/
|
|
11174
|
-
import {
|
|
11175
|
-
import
|
|
11176
|
-
import {
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
var
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
var TRANSITION_MS2 = 350;
|
|
11191
|
-
var HierarchicalEdgeBundling = ({ classNames, data, edges = [], label = (d) => d.label ?? d.id, padding = 120, tension = 0.85, r = 4, slots = defaultTreeLayoutSlots, onNodeHover }) => {
|
|
11192
|
-
const svgRef = useRef4(null);
|
|
11193
|
-
const { setRef, width, height } = useContainerSize();
|
|
11194
|
-
const root = useMemo3(() => buildBundleHierarchy(data, edges), [
|
|
11195
|
-
data,
|
|
11196
|
-
edges
|
|
11197
|
-
]);
|
|
11198
|
-
const handleHoverRef = useRef4(() => {
|
|
11199
|
-
});
|
|
11200
|
-
handleHoverRef.current = (node, event) => onNodeHover?.(node, event);
|
|
11201
|
-
useEffect7(() => {
|
|
11202
|
-
if (!svgRef.current || !width || !height) {
|
|
11203
|
-
return;
|
|
11204
|
-
}
|
|
11205
|
-
const radius = Math.max(0, Math.min(width, height) / 2 - padding);
|
|
11206
|
-
renderBundling(svgRef.current, root, {
|
|
11207
|
-
radius,
|
|
11208
|
-
r,
|
|
11209
|
-
label,
|
|
11210
|
-
slots,
|
|
11211
|
-
tension,
|
|
11212
|
-
onNodeHover: (n, e) => handleHoverRef.current(n, e)
|
|
11213
|
-
});
|
|
11214
|
-
}, [
|
|
11215
|
-
root,
|
|
11216
|
-
width,
|
|
11217
|
-
height,
|
|
11218
|
-
padding,
|
|
11219
|
-
tension,
|
|
11220
|
-
r,
|
|
11221
|
-
label,
|
|
11222
|
-
slots
|
|
11223
|
-
]);
|
|
11224
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
11225
|
-
ref: setRef,
|
|
11226
|
-
className: mx("dx-expander relative", classNames)
|
|
11227
|
-
}, width > 0 && height > 0 && /* @__PURE__ */ React6.createElement("svg", {
|
|
11228
|
-
ref: svgRef,
|
|
11229
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
11230
|
-
width,
|
|
11231
|
-
height,
|
|
11232
|
-
viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
|
|
11233
|
-
}));
|
|
11234
|
-
};
|
|
11235
|
-
var buildBundleHierarchy = (data, edges) => {
|
|
11236
|
-
const root = hierarchy(data);
|
|
11237
|
-
const byId = /* @__PURE__ */ new Map();
|
|
11238
|
-
for (const node of root.descendants()) {
|
|
11239
|
-
byId.set(node.data.id, node);
|
|
11240
|
-
node.outgoing = [];
|
|
11241
|
-
node.incoming = [];
|
|
11152
|
+
// src/components/Visualization/variants.ts
|
|
11153
|
+
import { curveCatmullRom, line as d3Line } from "d3";
|
|
11154
|
+
import { Obj as Obj4 } from "@dxos/echo";
|
|
11155
|
+
import { CLUSTER_NODE_TYPE_LEAF, CLUSTER_NODE_TYPE_ROOT, GraphBundleProjector, GraphClusterProjector, GraphForceProjector as GraphForceProjector2, GraphLatticeProjector, GraphPlexusProjector, GraphSwarmProjector, GraphTreeProjector, PLEXUS_NODE_TYPE_FOCUS, PLEXUS_NODE_TYPE_RELATION, TREE_NODE_TYPE_INBOUND, TREE_NODE_TYPE_ROOT, appendRadialGroupLabel, appendRadialLeafLabel, appendRootLabel } from "@dxos/react-ui-graph";
|
|
11156
|
+
var TWEEN_MS = 500;
|
|
11157
|
+
var LABEL_FADE_MS = 200;
|
|
11158
|
+
var PLEXUS_LEAF_RADIUS = 5;
|
|
11159
|
+
var PLEXUS_FOCUS_RADIUS = PLEXUS_LEAF_RADIUS * 2;
|
|
11160
|
+
var TREE_NODE_RADIUS = 6;
|
|
11161
|
+
var TREE_ROOT_RADIUS = TREE_NODE_RADIUS * 2;
|
|
11162
|
+
var swarmTrailLine = d3Line().curve(curveCatmullRom.alpha(0.5));
|
|
11163
|
+
var applyNodeSwarm = (group, node) => {
|
|
11164
|
+
const swarm = node;
|
|
11165
|
+
const path = group.querySelector("path.dx-swarm-tail");
|
|
11166
|
+
const grad = group.querySelector("linearGradient");
|
|
11167
|
+
if (!path || !grad) {
|
|
11168
|
+
return;
|
|
11242
11169
|
}
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11170
|
+
const history = swarm.history ?? [];
|
|
11171
|
+
if (history.length === 0) {
|
|
11172
|
+
path.setAttribute("d", "");
|
|
11173
|
+
return;
|
|
11174
|
+
}
|
|
11175
|
+
const hx = swarm.x ?? 0;
|
|
11176
|
+
const hy = swarm.y ?? 0;
|
|
11177
|
+
const points = [
|
|
11178
|
+
[
|
|
11179
|
+
0,
|
|
11180
|
+
0
|
|
11181
|
+
]
|
|
11182
|
+
];
|
|
11183
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
11184
|
+
points.push([
|
|
11185
|
+
history[i].x - hx,
|
|
11186
|
+
history[i].y - hy
|
|
11258
11187
|
]);
|
|
11259
11188
|
}
|
|
11260
|
-
|
|
11189
|
+
path.setAttribute("d", swarmTrailLine(points) ?? "");
|
|
11190
|
+
const oldest = history[0];
|
|
11191
|
+
grad.setAttribute("x2", String(oldest.x - hx));
|
|
11192
|
+
grad.setAttribute("y2", String(oldest.y - hy));
|
|
11261
11193
|
};
|
|
11262
|
-
var
|
|
11263
|
-
const
|
|
11264
|
-
const
|
|
11265
|
-
if (!
|
|
11266
|
-
|
|
11267
|
-
return;
|
|
11194
|
+
var plexusRelationOf = (edge, focusId) => {
|
|
11195
|
+
const outgoing = edge.source.id === focusId;
|
|
11196
|
+
const incoming = edge.target.id === focusId;
|
|
11197
|
+
if (!outgoing && !incoming) {
|
|
11198
|
+
return void 0;
|
|
11268
11199
|
}
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
}
|
|
11288
|
-
|
|
11289
|
-
d[0].pathEl = this;
|
|
11290
|
-
}).transition().duration(TRANSITION_MS2).attr("opacity", 1).attr("d", ([s, t]) => line(s.path(t)));
|
|
11291
|
-
const labels = nodesLayer.selectAll("g.dx-bundle-leaf").data(leaves, (d) => d.data.id).join((enter) => {
|
|
11292
|
-
const ge = enter.append("g").classed("dx-bundle-leaf", true).attr("opacity", 0);
|
|
11293
|
-
ge.append("circle").style("cursor", "pointer");
|
|
11294
|
-
ge.append("text").attr("dy", "0.32em").attr("paint-order", "stroke").style("cursor", "pointer");
|
|
11295
|
-
return ge;
|
|
11296
|
-
}, (update) => update, (exit) => exit.each(function() {
|
|
11297
|
-
select2(this).interrupt();
|
|
11298
|
-
}).transition().duration(TRANSITION_MS2).attr("opacity", 0).remove());
|
|
11299
|
-
labels.transition().duration(TRANSITION_MS2).attr("opacity", 1).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`);
|
|
11300
|
-
const onEnter = function(event, d) {
|
|
11301
|
-
onNodeHover(d.data, event);
|
|
11302
|
-
hover(linksLayer, leaves, d, true);
|
|
11303
|
-
};
|
|
11304
|
-
const onLeave = function(event, d) {
|
|
11305
|
-
onNodeHover(null);
|
|
11306
|
-
hover(linksLayer, leaves, d, false);
|
|
11307
|
-
};
|
|
11308
|
-
labels.select("circle").attr("class", [
|
|
11309
|
-
slots.node ?? "",
|
|
11310
|
-
"dx-leaf"
|
|
11311
|
-
].filter(Boolean).join(" ")).attr("r", r).style("fill", (d) => getNodeFillForObject(d.data.data)).each(function(d) {
|
|
11312
|
-
d.circle = this;
|
|
11313
|
-
}).on("pointerenter", onEnter).on("pointerleave", onLeave);
|
|
11314
|
-
labels.select("text").attr("class", slots.text ?? "").attr("x", (d) => d.x < Math.PI ? r + 4 : -(r + 4)).attr("text-anchor", (d) => d.x < Math.PI ? "start" : "end").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).each(function(d) {
|
|
11315
|
-
d.text = this;
|
|
11316
|
-
}).text((d) => label(d.data)).on("pointerenter", onEnter).on("pointerleave", onLeave);
|
|
11200
|
+
const direction = outgoing ? "out" : "in";
|
|
11201
|
+
const arrow = outgoing ? "\u2192" : "\u2190";
|
|
11202
|
+
if (edge.type === "relation") {
|
|
11203
|
+
const relation = edge.data?.object;
|
|
11204
|
+
const typename = relation ? Obj4.getTypename(relation) : void 0;
|
|
11205
|
+
const name = typename ? shortTypename(typename) : "Relation";
|
|
11206
|
+
return {
|
|
11207
|
+
key: `relation:${direction}:${typename ?? "?"}`,
|
|
11208
|
+
label: `${name} ${arrow}`
|
|
11209
|
+
};
|
|
11210
|
+
}
|
|
11211
|
+
if (edge.type === "ref") {
|
|
11212
|
+
const property = edge.data?.property;
|
|
11213
|
+
const name = property ?? "References";
|
|
11214
|
+
return {
|
|
11215
|
+
key: `ref:${direction}:${property ?? "?"}`,
|
|
11216
|
+
label: `${name} ${arrow}`
|
|
11217
|
+
};
|
|
11218
|
+
}
|
|
11219
|
+
return void 0;
|
|
11317
11220
|
};
|
|
11318
|
-
var
|
|
11319
|
-
const
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11221
|
+
var typenameGroupOf = (node) => {
|
|
11222
|
+
const obj = node.data?.data?.object;
|
|
11223
|
+
return obj ? Obj4.getTypename(obj) ?? "(untyped)" : void 0;
|
|
11224
|
+
};
|
|
11225
|
+
var shortTypename = (typename) => {
|
|
11226
|
+
const last = typename.split(".").pop() ?? typename;
|
|
11227
|
+
return last.charAt(0).toUpperCase() + last.slice(1);
|
|
11228
|
+
};
|
|
11229
|
+
var labelForLeaf = (node, obj) => (obj && Obj4.getLabel(obj)) ?? node.data?.data?.label ?? node.id;
|
|
11230
|
+
var appendTreeLabel = (group, text, r, placement) => {
|
|
11231
|
+
const offset = r + 4;
|
|
11232
|
+
const label = group.append("text").attr("class", "dx-cluster-label").attr("opacity", 0).style("cursor", "pointer");
|
|
11233
|
+
if (placement === "above") {
|
|
11234
|
+
label.attr("x", 0).attr("y", -offset).attr("text-anchor", "middle");
|
|
11235
|
+
} else {
|
|
11236
|
+
const toLeft = placement === "left";
|
|
11237
|
+
label.attr("dy", "0.32em").attr("x", toLeft ? -offset : offset).attr("text-anchor", toLeft ? "end" : "start");
|
|
11238
|
+
}
|
|
11239
|
+
label.text(text).transition().delay(TWEEN_MS).duration(LABEL_FADE_MS).attr("opacity", 1);
|
|
11240
|
+
};
|
|
11241
|
+
var DEFINITIONS = {
|
|
11242
|
+
force: {
|
|
11243
|
+
value: "force",
|
|
11244
|
+
icon: "ph--graph--regular",
|
|
11245
|
+
label: "Force-directed",
|
|
11246
|
+
drag: true,
|
|
11247
|
+
emitsHover: true,
|
|
11248
|
+
// Force has no `duration` — its own simulation drives motion via ticks.
|
|
11249
|
+
createProjector: (ctx, { prev }) => new GraphForceProjector2(ctx, void 0, void 0, prev),
|
|
11250
|
+
renderNode: (group, node) => {
|
|
11251
|
+
const r = node.r ?? 6;
|
|
11252
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", getNodeFillForObject(node.data?.data?.object));
|
|
11330
11253
|
}
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11254
|
+
},
|
|
11255
|
+
cluster: {
|
|
11256
|
+
value: "cluster",
|
|
11257
|
+
icon: "ph--asterisk-simple--regular",
|
|
11258
|
+
label: "Radial",
|
|
11259
|
+
emitsHover: true,
|
|
11260
|
+
createProjector: (ctx, { prev }) => new GraphClusterProjector(ctx, {
|
|
11261
|
+
duration: TWEEN_MS,
|
|
11262
|
+
groupOf: typenameGroupOf,
|
|
11263
|
+
rootLabel: "Database",
|
|
11264
|
+
groupLabel: shortTypename,
|
|
11265
|
+
// All three node kinds share the same radius — leaves, groups, and root read
|
|
11266
|
+
// as members of the same circle rather than ranked by size.
|
|
11267
|
+
rootRadius: 4,
|
|
11268
|
+
groupRadius: 4
|
|
11269
|
+
}, void 0, prev),
|
|
11270
|
+
renderNode: (group, node) => {
|
|
11271
|
+
const obj = node.data?.data?.object;
|
|
11272
|
+
const r = node.r ?? 4;
|
|
11273
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", obj ? getNodeFillForObject(obj) : "var(--color-neutral-500)");
|
|
11274
|
+
const labelOptions = {
|
|
11275
|
+
delay: TWEEN_MS,
|
|
11276
|
+
duration: LABEL_FADE_MS
|
|
11277
|
+
};
|
|
11278
|
+
if (node.type === CLUSTER_NODE_TYPE_LEAF) {
|
|
11279
|
+
const text = labelForLeaf(node, obj);
|
|
11280
|
+
if (text) {
|
|
11281
|
+
appendRadialLeafLabel(group, node, text, r, labelOptions);
|
|
11341
11282
|
}
|
|
11342
|
-
|
|
11343
|
-
|
|
11283
|
+
} else if (node.type === CLUSTER_NODE_TYPE_ROOT) {
|
|
11284
|
+
if (node.label) {
|
|
11285
|
+
appendRootLabel(group, node.label, r, labelOptions);
|
|
11344
11286
|
}
|
|
11345
|
-
|
|
11346
|
-
|
|
11287
|
+
} else {
|
|
11288
|
+
if (node.label) {
|
|
11289
|
+
appendRadialGroupLabel(group, node, node.label, r, labelOptions);
|
|
11290
|
+
}
|
|
11291
|
+
}
|
|
11292
|
+
}
|
|
11293
|
+
},
|
|
11294
|
+
bundle: {
|
|
11295
|
+
value: "bundle",
|
|
11296
|
+
icon: "ph--circles-three-plus--regular",
|
|
11297
|
+
label: "Connections",
|
|
11298
|
+
highlightOnHover: true,
|
|
11299
|
+
emitsHover: true,
|
|
11300
|
+
createProjector: (ctx, { prev }) => new GraphBundleProjector(ctx, {
|
|
11301
|
+
duration: TWEEN_MS,
|
|
11302
|
+
groupOf: typenameGroupOf
|
|
11303
|
+
}, void 0, prev),
|
|
11304
|
+
// Bundle layout renders ONLY leaves (root/group are invisible routing anchors).
|
|
11305
|
+
renderNode: (group, node) => {
|
|
11306
|
+
const obj = node.data?.data?.object;
|
|
11307
|
+
const r = node.r ?? 4;
|
|
11308
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", obj ? getNodeFillForObject(obj) : "var(--color-neutral-500)");
|
|
11309
|
+
const text = labelForLeaf(node, obj);
|
|
11310
|
+
if (text) {
|
|
11311
|
+
appendRadialLeafLabel(group, node, text, r, {
|
|
11312
|
+
delay: TWEEN_MS,
|
|
11313
|
+
duration: LABEL_FADE_MS
|
|
11314
|
+
});
|
|
11315
|
+
}
|
|
11316
|
+
}
|
|
11317
|
+
},
|
|
11318
|
+
plexus: {
|
|
11319
|
+
value: "plexus",
|
|
11320
|
+
icon: "ph--share-network--regular",
|
|
11321
|
+
label: "Plexus",
|
|
11322
|
+
focusable: true,
|
|
11323
|
+
// No focus → dispatch to the bundle projector (the unfocused overview). Once a node is
|
|
11324
|
+
// focused, switch to the focus-centric plexus layout; both receive `prev` so the swap
|
|
11325
|
+
// (and every re-focus) animates from the previous node positions.
|
|
11326
|
+
createProjector: (ctx, { focusId, prev }) => {
|
|
11327
|
+
if (!focusId) {
|
|
11328
|
+
return new GraphBundleProjector(ctx, {
|
|
11329
|
+
duration: TWEEN_MS,
|
|
11330
|
+
groupOf: typenameGroupOf
|
|
11331
|
+
}, void 0, prev);
|
|
11332
|
+
}
|
|
11333
|
+
return new GraphPlexusProjector(ctx, {
|
|
11334
|
+
duration: TWEEN_MS,
|
|
11335
|
+
focus: focusId,
|
|
11336
|
+
relationOf: plexusRelationOf,
|
|
11337
|
+
leafRadius: PLEXUS_LEAF_RADIUS,
|
|
11338
|
+
relationRadius: PLEXUS_LEAF_RADIUS,
|
|
11339
|
+
focusRadius: PLEXUS_FOCUS_RADIUS
|
|
11340
|
+
}, void 0, prev);
|
|
11341
|
+
},
|
|
11342
|
+
// Three node kinds: the focus at the centre (larger, object fill), synthetic relation
|
|
11343
|
+
// nodes on the inner ring (neutral, labelled by relation/property), and object leaves on
|
|
11344
|
+
// the outer ring (object fill). Type tags are set by the projector.
|
|
11345
|
+
renderNode: (group, node) => {
|
|
11346
|
+
const obj = node.data?.data?.object;
|
|
11347
|
+
const labelOptions = {
|
|
11348
|
+
delay: TWEEN_MS,
|
|
11349
|
+
duration: LABEL_FADE_MS
|
|
11350
|
+
};
|
|
11351
|
+
if (node.type === PLEXUS_NODE_TYPE_RELATION) {
|
|
11352
|
+
const r2 = PLEXUS_LEAF_RADIUS;
|
|
11353
|
+
group.append("circle").attr("r", r2).style("cursor", "default").style("fill", "var(--color-neutral-500)");
|
|
11354
|
+
if (node.label) {
|
|
11355
|
+
appendRadialGroupLabel(group, node, node.label, r2, labelOptions);
|
|
11347
11356
|
}
|
|
11348
|
-
|
|
11349
|
-
|
|
11357
|
+
return;
|
|
11358
|
+
}
|
|
11359
|
+
const isFocus = node.type === PLEXUS_NODE_TYPE_FOCUS;
|
|
11360
|
+
const r = isFocus ? PLEXUS_FOCUS_RADIUS : PLEXUS_LEAF_RADIUS;
|
|
11361
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", obj ? getNodeFillForObject(obj) : "var(--color-neutral-500)");
|
|
11362
|
+
const text = labelForLeaf(node, obj);
|
|
11363
|
+
if (text) {
|
|
11364
|
+
if (isFocus) {
|
|
11365
|
+
appendRootLabel(group, text, r, labelOptions);
|
|
11366
|
+
} else {
|
|
11367
|
+
appendRadialLeafLabel(group, node, text, r, labelOptions);
|
|
11350
11368
|
}
|
|
11351
|
-
|
|
11352
|
-
}).style("font-weight", () => on && leaf === focused ? "600" : null);
|
|
11369
|
+
}
|
|
11353
11370
|
}
|
|
11354
|
-
|
|
11355
|
-
|
|
11371
|
+
},
|
|
11372
|
+
lattice: {
|
|
11373
|
+
value: "lattice",
|
|
11374
|
+
icon: "ph--grid-four--regular",
|
|
11375
|
+
label: "Lattice",
|
|
11376
|
+
emitsHover: true,
|
|
11377
|
+
createProjector: (ctx, { prev }) => new GraphLatticeProjector(ctx, {
|
|
11378
|
+
duration: TWEEN_MS,
|
|
11379
|
+
// Plugin-explorer overrides the projector's force-matched default (6)
|
|
11380
|
+
// with a smaller node so the lattice reads as a dense matrix.
|
|
11381
|
+
radius: 4,
|
|
11382
|
+
// Cluster by typename first so same-type rects sit together; break ties by label.
|
|
11383
|
+
sortBy: (node) => {
|
|
11384
|
+
const obj = node.data?.data?.object;
|
|
11385
|
+
const typename = obj ? Obj4.getTypename(obj) ?? "(untyped)" : "(untyped)";
|
|
11386
|
+
const label = (obj && Obj4.getLabel(obj)) ?? node.data?.data?.label ?? node.id;
|
|
11387
|
+
return `${typename} ${label}`;
|
|
11388
|
+
}
|
|
11389
|
+
}, void 0, prev),
|
|
11390
|
+
renderNode: (group, node) => {
|
|
11391
|
+
const r = node.r ?? 6;
|
|
11392
|
+
const sz = r * 2;
|
|
11393
|
+
group.append("rect").attr("x", -r).attr("y", -r).attr("width", sz).attr("height", sz).attr("rx", r * 0.3).attr("ry", r * 0.3).style("cursor", "pointer").style("fill", getNodeFillForObject(node.data?.data?.object));
|
|
11356
11394
|
}
|
|
11357
|
-
}
|
|
11358
|
-
|
|
11359
|
-
|
|
11360
|
-
|
|
11361
|
-
|
|
11362
|
-
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11395
|
+
},
|
|
11396
|
+
swarm: {
|
|
11397
|
+
value: "swarm",
|
|
11398
|
+
icon: "ph--microscope--regular",
|
|
11399
|
+
label: "Swarm",
|
|
11400
|
+
edgeOpacity: 0.3,
|
|
11401
|
+
trackPointer: true,
|
|
11402
|
+
emitsHover: true,
|
|
11403
|
+
applyNode: applyNodeSwarm,
|
|
11404
|
+
// Swarm in SVG: a per-tick projector mirroring force's emit-positions pattern.
|
|
11405
|
+
createProjector: (ctx, { prev }) => new GraphSwarmProjector(ctx, void 0, void 0, prev),
|
|
11406
|
+
// Match the force variant's shape so identity-by-id transitions read continuously.
|
|
11407
|
+
// The tail is a SINGLE `<path>` traced through head + history points; its stroke
|
|
11408
|
+
// uses a per-boid `<linearGradient>` that fades head → tail. Done this way (rather
|
|
11409
|
+
// than as N overlapping `<line>` segments) so coincident segment endpoints don't
|
|
11410
|
+
// compound their alpha and read as a striped trail.
|
|
11411
|
+
renderNode: (group, node) => {
|
|
11412
|
+
const fill = getNodeFillForObject(node.data?.data?.object);
|
|
11413
|
+
const r = node.r ?? 6;
|
|
11414
|
+
const strokeWidth = Math.max(1, r * 0.6);
|
|
11415
|
+
const gradId = `dx-swarm-grad-${String(node.id).replace(/[^\w-]/g, "_")}`;
|
|
11416
|
+
const grad = group.append("defs").append("linearGradient").attr("id", gradId).attr("gradientUnits", "userSpaceOnUse").attr("x1", 0).attr("y1", 0).attr("x2", 0).attr("y2", 0);
|
|
11417
|
+
grad.append("stop").attr("offset", 0).attr("stop-color", fill).attr("stop-opacity", 0.7);
|
|
11418
|
+
grad.append("stop").attr("offset", 1).attr("stop-color", fill).attr("stop-opacity", 0);
|
|
11419
|
+
group.append("path").classed("dx-swarm-tail", true).attr("fill", "none").attr("stroke", `url(#${gradId})`).attr("stroke-width", strokeWidth).attr("stroke-linecap", "round").attr("stroke-linejoin", "round").attr("pointer-events", "none");
|
|
11420
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", fill);
|
|
11371
11421
|
}
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
//
|
|
11379
|
-
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11422
|
+
},
|
|
11423
|
+
neighborhood: {
|
|
11424
|
+
value: "neighborhood",
|
|
11425
|
+
icon: "ph--tree-structure--regular",
|
|
11426
|
+
label: "Neighborhood",
|
|
11427
|
+
emitsHover: true,
|
|
11428
|
+
// Tidy tree: the active node (passed as `focusId`) is the root, drawn on the left and vertically
|
|
11429
|
+
// centred; the pre-traversed n-hop neighbourhood fans out to the right. No focus → plain ring.
|
|
11430
|
+
createProjector: (ctx, { focusId, prev }) => new GraphTreeProjector(ctx, {
|
|
11431
|
+
duration: TWEEN_MS,
|
|
11432
|
+
focus: focusId,
|
|
11433
|
+
nodeRadius: TREE_NODE_RADIUS,
|
|
11434
|
+
rootRadius: TREE_ROOT_RADIUS
|
|
11435
|
+
}, void 0, prev),
|
|
11436
|
+
renderNode: (group, node) => {
|
|
11437
|
+
const obj = node.data?.data?.object;
|
|
11438
|
+
const isRoot = node.type === TREE_NODE_TYPE_ROOT;
|
|
11439
|
+
const r = isRoot ? TREE_ROOT_RADIUS : TREE_NODE_RADIUS;
|
|
11440
|
+
group.append("circle").attr("r", r).style("cursor", "pointer").style("fill", obj ? getNodeFillForObject(obj) : "var(--color-neutral-500)");
|
|
11441
|
+
const text = labelForLeaf(node, obj);
|
|
11442
|
+
if (text) {
|
|
11443
|
+
const placement = isRoot ? "above" : node.type === TREE_NODE_TYPE_INBOUND ? "left" : "right";
|
|
11444
|
+
appendTreeLabel(group, text, r, placement);
|
|
11391
11445
|
}
|
|
11392
|
-
return next;
|
|
11393
|
-
});
|
|
11394
|
-
}, []);
|
|
11395
|
-
const handleClickRef = useRef5(() => {
|
|
11396
|
-
});
|
|
11397
|
-
handleClickRef.current = (node) => {
|
|
11398
|
-
onNodeClick?.(node);
|
|
11399
|
-
if (node.children?.length) {
|
|
11400
|
-
toggle(node.id);
|
|
11401
11446
|
}
|
|
11402
|
-
}
|
|
11403
|
-
|
|
11447
|
+
}
|
|
11448
|
+
};
|
|
11449
|
+
var VARIANTS = [
|
|
11450
|
+
"force",
|
|
11451
|
+
"cluster",
|
|
11452
|
+
"bundle",
|
|
11453
|
+
"plexus",
|
|
11454
|
+
"lattice",
|
|
11455
|
+
"swarm"
|
|
11456
|
+
].map((id) => DEFINITIONS[id]);
|
|
11457
|
+
var getVariant = (value) => DEFINITIONS[value];
|
|
11458
|
+
var isVariant = (value) => VARIANTS.some((variant) => variant.value === value);
|
|
11459
|
+
|
|
11460
|
+
// src/components/Visualization/Visualization.tsx
|
|
11461
|
+
var [VisualizationProvider, useVisualizationContext] = createContext("Visualization.Root");
|
|
11462
|
+
var VisualizationRoot = slottable(({ children, asChild, model, variant, focus, onSurfaceClick, ...props }, forwardedRef) => {
|
|
11463
|
+
const { className, ...rest } = composableProps3(props, {
|
|
11464
|
+
classNames: "dx-expander relative"
|
|
11404
11465
|
});
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11466
|
+
const Comp = asChild ? Slot : "div";
|
|
11467
|
+
return /* @__PURE__ */ React6.createElement(VisualizationProvider, {
|
|
11468
|
+
model,
|
|
11469
|
+
variant: getVariant(variant),
|
|
11470
|
+
focus
|
|
11471
|
+
}, /* @__PURE__ */ React6.createElement(Comp, {
|
|
11472
|
+
...rest,
|
|
11473
|
+
className,
|
|
11474
|
+
onClick: onSurfaceClick,
|
|
11475
|
+
ref: forwardedRef
|
|
11476
|
+
}, children));
|
|
11477
|
+
});
|
|
11478
|
+
VisualizationRoot.displayName = "Visualization.Root";
|
|
11479
|
+
var VisualizationGraph = ({ debug = false, onNodeHover }) => {
|
|
11480
|
+
const { model, variant, focus } = useVisualizationContext("Visualization.Graph");
|
|
11481
|
+
const svgRef = useRef4(null);
|
|
11482
|
+
const [projector, setProjector] = useState3();
|
|
11483
|
+
const projectorRef = useRef4(void 0);
|
|
11484
|
+
projectorRef.current = projector;
|
|
11485
|
+
const [clickFocusId, setClickFocusId] = useState3(void 0);
|
|
11486
|
+
const focusId = focus ?? clickFocusId;
|
|
11487
|
+
const lastLayoutRef = useRef4(void 0);
|
|
11488
|
+
useEffect6(() => model?.subscribe(() => void 0), [
|
|
11489
|
+
model
|
|
11409
11490
|
]);
|
|
11410
|
-
|
|
11411
|
-
if (!
|
|
11412
|
-
|
|
11491
|
+
useEffect6(() => {
|
|
11492
|
+
if (!variant.focusable) {
|
|
11493
|
+
setClickFocusId(void 0);
|
|
11413
11494
|
}
|
|
11414
|
-
const radius = Math.max(0, Math.min(width, height) / 2 - padding);
|
|
11415
|
-
renderRadialTree(svgRef.current, root, {
|
|
11416
|
-
radius,
|
|
11417
|
-
r,
|
|
11418
|
-
label,
|
|
11419
|
-
slots,
|
|
11420
|
-
collapsed,
|
|
11421
|
-
cluster: cluster2,
|
|
11422
|
-
onNodeClick: (n) => handleClickRef.current(n),
|
|
11423
|
-
onNodeHover: (n, e) => handleHoverRef.current(n, e)
|
|
11424
|
-
});
|
|
11425
11495
|
}, [
|
|
11426
|
-
|
|
11427
|
-
width,
|
|
11428
|
-
height,
|
|
11429
|
-
r,
|
|
11430
|
-
padding,
|
|
11431
|
-
label,
|
|
11432
|
-
slots,
|
|
11433
|
-
collapsed,
|
|
11434
|
-
cluster2
|
|
11496
|
+
variant
|
|
11435
11497
|
]);
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
}, width > 0 && height > 0 && /* @__PURE__ */ React7.createElement("svg", {
|
|
11440
|
-
ref: svgRef,
|
|
11441
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
11442
|
-
width,
|
|
11443
|
-
height,
|
|
11444
|
-
viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
|
|
11445
|
-
}));
|
|
11446
|
-
};
|
|
11447
|
-
var renderRadialTree = (svgElement, root, options) => {
|
|
11448
|
-
const { radius, r, label, slots, collapsed, cluster: cluster2, onNodeClick, onNodeHover } = options;
|
|
11449
|
-
const svg = select3(svgElement);
|
|
11450
|
-
const layout = cluster2 ? d3Cluster() : d3Tree();
|
|
11451
|
-
layout.size([
|
|
11452
|
-
2 * Math.PI,
|
|
11453
|
-
radius
|
|
11454
|
-
]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / Math.max(1, a.depth))(root);
|
|
11455
|
-
const g = svg.selectAll("g.dx-radial-root").data([
|
|
11456
|
-
null
|
|
11457
|
-
]).join("g").classed("dx-radial-root", true);
|
|
11458
|
-
const linksLayer = g.selectAll("g.dx-radial-links").data([
|
|
11459
|
-
null
|
|
11460
|
-
]).join("g").classed("dx-radial-links", true);
|
|
11461
|
-
const nodesLayer = g.selectAll("g.dx-radial-nodes").data([
|
|
11462
|
-
null
|
|
11463
|
-
]).join("g").classed("dx-radial-nodes", true);
|
|
11464
|
-
const linkPath = linkRadial().angle((d) => d.x).radius((d) => d.y);
|
|
11465
|
-
linksLayer.selectAll("path").data(root.links(), (d) => `${d.source.data.id}->${d.target.data.id}`).join((enter) => enter.append("path").attr("class", slots.path ?? "").attr("fill", "none").attr("opacity", 0), (update) => update, (exit) => exit.transition().duration(TRANSITION_MS3).attr("opacity", 0).remove()).transition().duration(TRANSITION_MS3).attr("opacity", 1).attr("d", linkPath);
|
|
11466
|
-
const node = nodesLayer.selectAll("g.dx-radial-node").data(root.descendants(), (d) => d.data.id);
|
|
11467
|
-
const nodeEnter = node.enter().append("g").classed("dx-radial-node", true).attr("opacity", 0).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`).style("cursor", (d) => d.data.children?.length ? "pointer" : "default").on("click", (_, d) => onNodeClick(d.data));
|
|
11468
|
-
nodeEnter.append("circle").attr("r", r).on("pointerenter", (event, d) => onNodeHover(d.data, event)).on("pointerleave", (event) => onNodeHover(null, event));
|
|
11469
|
-
nodeEnter.append("text").attr("dy", "0.32em").attr("paint-order", "stroke").text((d) => label(d.data));
|
|
11470
|
-
const nodeMerge = nodeEnter.merge(node);
|
|
11471
|
-
nodeMerge.transition().duration(TRANSITION_MS3).attr("opacity", 1).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`);
|
|
11472
|
-
nodeMerge.select("circle").attr("class", (d) => {
|
|
11473
|
-
const collapsedHere = isCollapsed(d.data, collapsed);
|
|
11474
|
-
const leaf = isLeaf(d.data);
|
|
11475
|
-
return [
|
|
11476
|
-
slots.node ?? "",
|
|
11477
|
-
collapsedHere ? "dx-collapsed" : leaf ? "dx-leaf" : "dx-branch"
|
|
11478
|
-
].filter(Boolean).join(" ");
|
|
11479
|
-
}).attr("r", r).style("fill", (d) => isLeaf(d.data) ? getNodeFillForObject(d.data.data) : null);
|
|
11480
|
-
nodeMerge.select("text").attr("class", slots.text ?? "").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).attr("x", (d) => d.x < Math.PI === !d.children ? r + 4 : -(r + 4)).attr("text-anchor", (d) => d.x < Math.PI === !d.children ? "start" : "end").text((d) => label(d.data));
|
|
11481
|
-
node.exit().transition().duration(TRANSITION_MS3).attr("opacity", 0).remove();
|
|
11482
|
-
};
|
|
11483
|
-
|
|
11484
|
-
// src/components/Tree/layout/TidyTree.tsx
|
|
11485
|
-
import { curveBumpX, link as d3Link, select as select4, tree as d3Tree2 } from "d3";
|
|
11486
|
-
import React8, { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo5, useRef as useRef6, useState as useState5 } from "react";
|
|
11487
|
-
import { mx as mx3 } from "@dxos/ui-theme";
|
|
11488
|
-
var TRANSITION_MS4 = 350;
|
|
11489
|
-
var TidyTree = ({ classNames, data, label = (d) => d.label ?? d.id, slots = defaultTreeLayoutSlots, r = 4, margin = 24, initialCollapsed, onNodeClick }) => {
|
|
11490
|
-
const svgRef = useRef6(null);
|
|
11491
|
-
const { setRef, width, height } = useContainerSize();
|
|
11492
|
-
const [collapsed, setCollapsed] = useState5(() => new Set(initialCollapsed ?? []));
|
|
11493
|
-
const toggle = useCallback4((id) => {
|
|
11494
|
-
setCollapsed((prev) => {
|
|
11495
|
-
const next = new Set(prev);
|
|
11496
|
-
if (next.has(id)) {
|
|
11497
|
-
next.delete(id);
|
|
11498
|
-
} else {
|
|
11499
|
-
next.add(id);
|
|
11500
|
-
}
|
|
11501
|
-
return next;
|
|
11502
|
-
});
|
|
11503
|
-
}, []);
|
|
11504
|
-
const handleClickRef = useRef6(() => {
|
|
11505
|
-
});
|
|
11506
|
-
handleClickRef.current = (node) => {
|
|
11507
|
-
onNodeClick?.(node);
|
|
11508
|
-
if (node.children?.length) {
|
|
11509
|
-
toggle(node.id);
|
|
11498
|
+
useEffect6(() => {
|
|
11499
|
+
if (projectorRef.current?.layout) {
|
|
11500
|
+
lastLayoutRef.current = projectorRef.current.layout;
|
|
11510
11501
|
}
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11502
|
+
if (!svgRef.current) {
|
|
11503
|
+
return;
|
|
11504
|
+
}
|
|
11505
|
+
setProjector(variant.createProjector(svgRef.current, {
|
|
11506
|
+
focusId,
|
|
11507
|
+
prev: lastLayoutRef.current
|
|
11508
|
+
}));
|
|
11509
|
+
}, [
|
|
11510
|
+
variant,
|
|
11511
|
+
focusId
|
|
11515
11512
|
]);
|
|
11516
|
-
|
|
11517
|
-
if (!
|
|
11513
|
+
const handleSelect = useCallback3((node) => {
|
|
11514
|
+
if (!variant.focusable || !node.data?.data?.object) {
|
|
11518
11515
|
return;
|
|
11519
11516
|
}
|
|
11520
|
-
|
|
11521
|
-
width,
|
|
11522
|
-
height,
|
|
11523
|
-
r,
|
|
11524
|
-
margin,
|
|
11525
|
-
label,
|
|
11526
|
-
slots,
|
|
11527
|
-
collapsed,
|
|
11528
|
-
onNodeClick: (n) => handleClickRef.current(n)
|
|
11529
|
-
});
|
|
11517
|
+
setClickFocusId((current) => current === node.id ? void 0 : node.id);
|
|
11530
11518
|
}, [
|
|
11531
|
-
|
|
11532
|
-
width,
|
|
11533
|
-
height,
|
|
11534
|
-
r,
|
|
11535
|
-
margin,
|
|
11536
|
-
label,
|
|
11537
|
-
slots,
|
|
11538
|
-
collapsed
|
|
11519
|
+
variant
|
|
11539
11520
|
]);
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
}, width > 0 && height > 0 && /* @__PURE__ */ React8.createElement("svg", {
|
|
11544
|
-
ref: svgRef,
|
|
11545
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
11546
|
-
width,
|
|
11547
|
-
height,
|
|
11548
|
-
viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
|
|
11549
|
-
}));
|
|
11550
|
-
};
|
|
11551
|
-
var renderTidyTree = (svgElement, root, options) => {
|
|
11552
|
-
const { width, height, r, margin, label, slots, collapsed, onNodeClick } = options;
|
|
11553
|
-
const svg = select4(svgElement);
|
|
11554
|
-
const dx = 18;
|
|
11555
|
-
const dy = Math.max(60, (width - margin * 2) / Math.max(1, root.height + 1));
|
|
11556
|
-
d3Tree2().nodeSize([
|
|
11557
|
-
dx,
|
|
11558
|
-
dy
|
|
11559
|
-
])(root);
|
|
11560
|
-
let x0 = Infinity;
|
|
11561
|
-
let x1 = -x0;
|
|
11562
|
-
root.each((d) => {
|
|
11563
|
-
if (d.x > x1) {
|
|
11564
|
-
x1 = d.x;
|
|
11521
|
+
const handlePointerMove = useCallback3((point) => {
|
|
11522
|
+
if (projector instanceof GraphSwarmProjector2) {
|
|
11523
|
+
projector.setCursor(point.x, point.y);
|
|
11565
11524
|
}
|
|
11566
|
-
|
|
11567
|
-
|
|
11525
|
+
}, [
|
|
11526
|
+
projector
|
|
11527
|
+
]);
|
|
11528
|
+
const handlePointerLeave = useCallback3(() => {
|
|
11529
|
+
if (projector instanceof GraphSwarmProjector2) {
|
|
11530
|
+
projector.setCursor(null);
|
|
11568
11531
|
}
|
|
11569
|
-
}
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
const
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
const g = svg.selectAll("g.dx-tidy-root").data([
|
|
11576
|
-
null
|
|
11577
|
-
]).join("g").classed("dx-tidy-root", true);
|
|
11578
|
-
const linksLayer = g.selectAll("g.dx-tidy-links").data([
|
|
11579
|
-
null
|
|
11580
|
-
]).join("g").classed("dx-tidy-links", true);
|
|
11581
|
-
const nodesLayer = g.selectAll("g.dx-tidy-nodes").data([
|
|
11582
|
-
null
|
|
11583
|
-
]).join("g").classed("dx-tidy-nodes", true);
|
|
11584
|
-
const linkPath = d3Link(curveBumpX).x((d) => offsetX + d.y).y((d) => (d.x + offsetY) * scaleY);
|
|
11585
|
-
linksLayer.selectAll("path").data(root.links(), (d) => `${d.source.data.id}->${d.target.data.id}`).join((enter) => enter.append("path").attr("class", slots.path ?? "").attr("fill", "none").attr("opacity", 0), (update) => update, (exit) => exit.transition().duration(TRANSITION_MS4).attr("opacity", 0).remove()).transition().duration(TRANSITION_MS4).attr("opacity", 1).attr("d", linkPath);
|
|
11586
|
-
const node = nodesLayer.selectAll("g.dx-tidy-node").data(root.descendants(), (d) => d.data.id);
|
|
11587
|
-
const nodeEnter = node.enter().append("g").classed("dx-tidy-node", true).attr("transform", (d) => `translate(${offsetX + d.y},${(d.x + offsetY) * scaleY})`).attr("opacity", 0).style("cursor", (d) => d.data.children?.length ? "pointer" : "default").on("click", (_, d) => onNodeClick(d.data));
|
|
11588
|
-
nodeEnter.append("circle").attr("r", r);
|
|
11589
|
-
nodeEnter.append("text").attr("dy", "0.32em").attr("x", (d) => d.children ? -(r + 4) : r + 4).attr("text-anchor", (d) => d.children ? "end" : "start").text((d) => label(d.data));
|
|
11590
|
-
const nodeMerge = nodeEnter.merge(node);
|
|
11591
|
-
nodeMerge.transition().duration(TRANSITION_MS4).attr("opacity", 1).attr("transform", (d) => `translate(${offsetX + d.y},${(d.x + offsetY) * scaleY})`);
|
|
11592
|
-
nodeMerge.select("circle").attr("class", (d) => {
|
|
11593
|
-
const collapsedHere = isCollapsed(d.data, collapsed);
|
|
11594
|
-
const leaf = isLeaf(d.data);
|
|
11595
|
-
return [
|
|
11596
|
-
slots.node ?? "",
|
|
11597
|
-
collapsedHere ? "dx-collapsed" : leaf ? "dx-leaf" : "dx-branch"
|
|
11598
|
-
].filter(Boolean).join(" ");
|
|
11599
|
-
}).attr("r", r);
|
|
11600
|
-
nodeMerge.select("text").attr("class", slots.text ?? "").attr("x", (d) => d.children ? -(r + 4) : r + 4).attr("text-anchor", (d) => d.children ? "end" : "start").text((d) => label(d.data));
|
|
11601
|
-
node.exit().each(function() {
|
|
11602
|
-
select4(this).interrupt();
|
|
11603
|
-
}).transition().duration(TRANSITION_MS4).attr("opacity", 0).remove();
|
|
11604
|
-
};
|
|
11605
|
-
|
|
11606
|
-
// src/components/Tree/Tree.tsx
|
|
11607
|
-
var Tree = ({ classNames, data, edges, variant = "tidy", label, slots, initialCollapsed, onNodeClick, onNodeHover }) => {
|
|
11608
|
-
return useMemo6(() => {
|
|
11609
|
-
switch (variant) {
|
|
11610
|
-
case "tidy":
|
|
11611
|
-
return /* @__PURE__ */ React9.createElement(TidyTree, {
|
|
11612
|
-
classNames,
|
|
11613
|
-
data,
|
|
11614
|
-
label,
|
|
11615
|
-
slots,
|
|
11616
|
-
initialCollapsed,
|
|
11617
|
-
onNodeClick
|
|
11618
|
-
});
|
|
11619
|
-
case "radial":
|
|
11620
|
-
return /* @__PURE__ */ React9.createElement(RadialTree, {
|
|
11621
|
-
classNames,
|
|
11622
|
-
data,
|
|
11623
|
-
label,
|
|
11624
|
-
slots,
|
|
11625
|
-
initialCollapsed,
|
|
11626
|
-
onNodeClick,
|
|
11627
|
-
onNodeHover
|
|
11628
|
-
});
|
|
11629
|
-
case "edge":
|
|
11630
|
-
return /* @__PURE__ */ React9.createElement(HierarchicalEdgeBundling, {
|
|
11631
|
-
classNames,
|
|
11632
|
-
data,
|
|
11633
|
-
edges: edges ?? [],
|
|
11634
|
-
label,
|
|
11635
|
-
slots,
|
|
11636
|
-
onNodeHover
|
|
11637
|
-
});
|
|
11532
|
+
}, [
|
|
11533
|
+
projector
|
|
11534
|
+
]);
|
|
11535
|
+
const handleInspect = useCallback3((node, event) => {
|
|
11536
|
+
if (!variant.emitsHover) {
|
|
11537
|
+
return;
|
|
11638
11538
|
}
|
|
11539
|
+
onNodeHover?.(node ? {
|
|
11540
|
+
id: node.id,
|
|
11541
|
+
data: node.data?.data?.object
|
|
11542
|
+
} : null, event);
|
|
11639
11543
|
}, [
|
|
11640
11544
|
variant,
|
|
11641
|
-
classNames,
|
|
11642
|
-
data,
|
|
11643
|
-
edges,
|
|
11644
|
-
label,
|
|
11645
|
-
slots,
|
|
11646
|
-
initialCollapsed,
|
|
11647
|
-
onNodeClick,
|
|
11648
11545
|
onNodeHover
|
|
11649
11546
|
]);
|
|
11547
|
+
const pointerProps = variant.trackPointer ? {
|
|
11548
|
+
onPointerMove: handlePointerMove,
|
|
11549
|
+
onPointerLeave: handlePointerLeave
|
|
11550
|
+
} : void 0;
|
|
11551
|
+
return /* @__PURE__ */ React6.createElement(SVG2.Root, {
|
|
11552
|
+
ref: svgRef
|
|
11553
|
+
}, /* @__PURE__ */ React6.createElement(SVG2.Zoom, {
|
|
11554
|
+
extent: [
|
|
11555
|
+
1 / 2,
|
|
11556
|
+
2
|
|
11557
|
+
]
|
|
11558
|
+
}, projector && /* @__PURE__ */ React6.createElement(SVG2.Graph, {
|
|
11559
|
+
model,
|
|
11560
|
+
projector,
|
|
11561
|
+
renderNode: variant.renderNode,
|
|
11562
|
+
applyNode: variant.applyNode,
|
|
11563
|
+
edgeOpacity: variant.edgeOpacity,
|
|
11564
|
+
drag: variant.drag,
|
|
11565
|
+
highlightOnHover: variant.highlightOnHover,
|
|
11566
|
+
onSelect: handleSelect,
|
|
11567
|
+
onInspect: handleInspect,
|
|
11568
|
+
...pointerProps
|
|
11569
|
+
})), debug && /* @__PURE__ */ React6.createElement(SVG2.FPS, null));
|
|
11570
|
+
};
|
|
11571
|
+
VisualizationGraph.displayName = "Visualization.Graph";
|
|
11572
|
+
var Visualization = {
|
|
11573
|
+
Root: VisualizationRoot,
|
|
11574
|
+
Graph: VisualizationGraph
|
|
11650
11575
|
};
|
|
11651
11576
|
export {
|
|
11652
11577
|
CanvasForceGraph,
|
|
11653
11578
|
Chart,
|
|
11654
11579
|
ForceGraph,
|
|
11655
11580
|
Globe,
|
|
11656
|
-
HierarchicalEdgeBundling,
|
|
11657
11581
|
Lattice,
|
|
11658
|
-
RadialTree,
|
|
11659
|
-
TidyTree,
|
|
11660
11582
|
Tree,
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11583
|
+
TreeNodeType,
|
|
11584
|
+
TreeType,
|
|
11585
|
+
VARIANTS,
|
|
11586
|
+
Visualization,
|
|
11587
|
+
getVariant,
|
|
11588
|
+
isVariant,
|
|
11665
11589
|
treeTypeToTreeNode
|
|
11666
11590
|
};
|
|
11667
11591
|
//# sourceMappingURL=index.mjs.map
|