@graphty/graphty-element 2.0.1 → 2.2.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.
- package/README.md +3 -3
- package/dist/ai.js +4 -4
- package/dist/catalog.js +5 -5
- package/dist/chunks/{AiManager-awS0MNr1.js → AiManager-DWwQiBQu.js} +5 -5
- package/dist/chunks/{Algorithm-BdcqHKps.js → Algorithm-RQ629NLb.js} +210 -92
- package/dist/chunks/{DataSource-DK4GZBKg.js → DataSource-DEg3igzS.js} +3 -3
- package/dist/chunks/{GraphSession-D87eymV8.js → GraphSession-CtqyVNsw.js} +2518 -2239
- package/dist/chunks/{GraphtyError-B3eKs4yg.js → GraphtyError-BwcnblTH.js} +10 -8
- package/dist/chunks/{GraphtyLogger-CK03SnJi.js → GraphtyLogger-5KEttFUo.js} +1 -1
- package/dist/chunks/{NodeStyle-CS7dj20m.js → NodeStyle-Cup9O1lu.js} +2 -1
- package/dist/chunks/{VoiceInputAdapter-CcnCmxo5.js → VoiceInputAdapter-mD0x3z7t.js} +1 -1
- package/dist/chunks/{XRPivotCameraController-UjMsbran.js → XRPivotCameraController-Clil9NhV.js} +2 -2
- package/dist/chunks/{cameras-BeIAlMWR.js → cameras-DFXNYBze.js} +2 -2
- package/dist/chunks/{capability-check-DcKFwS6q.js → capability-check-dXwQ_z5B.js} +1 -1
- package/dist/chunks/{detect-B-YbbP7i.js → detect-CqN0mC6u.js} +3 -3
- package/dist/chunks/{format-detection-DohSEZnb.js → format-detection-C8vbCSlS.js} +1 -1
- package/dist/chunks/{index-uohvGegX.js → index-2VIpMJZP.js} +1576 -1211
- package/dist/chunks/{paletteRegistry-B-oS4YxP.js → paletteRegistry-NrWOKT-A.js} +17 -17
- package/dist/chunks/{registry-DU-e49Y2.js → registry-CSba5QGJ.js} +1 -1
- package/dist/chunks/{scales-DvGid5Ln.js → scales-BUS7NWy2.js} +2206 -1357
- package/dist/custom-elements.json +1 -1
- package/dist/extend.js +26 -27
- package/dist/graphty-catalog.json +7 -4
- package/dist/graphty.bundle.js +36288 -34368
- package/dist/graphty.js +66 -64
- package/dist/index.d.ts +1 -1
- package/dist/logging.js +2 -2
- package/dist/schema.js +1 -1
- package/dist/session.d.ts +2 -1
- package/dist/session.js +37 -33
- package/dist/src/Edge.d.ts +1 -1
- package/dist/src/Graph.d.ts +41 -7
- package/dist/src/Node.d.ts +1 -1
- package/dist/src/acceleration/AccelerationController.d.ts +27 -0
- package/dist/src/acceleration/index.d.ts +1 -1
- package/dist/src/acceleration/narrow.d.ts +56 -0
- package/dist/src/acceleration/types.d.ts +88 -7
- package/dist/src/algorithms/Algorithm.d.ts +96 -2
- package/dist/src/algorithms/BFSAlgorithm.d.ts +9 -0
- package/dist/src/algorithms/DijkstraAlgorithm.d.ts +2 -8
- package/dist/src/algorithms/PageRankAlgorithm.d.ts +8 -0
- package/dist/src/algorithms/utils/graphUtils.d.ts +13 -0
- package/dist/src/cameras/OrbitCameraController.d.ts +1 -0
- package/dist/src/catalog/layouts.d.ts +13 -1
- package/dist/src/config/GraphBehavior.d.ts +13 -0
- package/dist/src/config/GraphStyle.d.ts +1 -1
- package/dist/src/config/StyleTemplate.d.ts +4 -0
- package/dist/src/data/CSVDataSource.d.ts +1 -0
- package/dist/src/data/csv-variant-detection.d.ts +11 -0
- package/dist/src/errors/codes.d.ts +14 -1
- package/dist/src/events.d.ts +17 -4
- package/dist/src/graphty-element.d.ts +48 -3
- package/dist/src/layout/ForceAtlas2LayoutEngine.d.ts +28 -45
- package/dist/src/layout/LayoutEngine.d.ts +7 -7
- package/dist/src/layout/SimulationLayoutEngine.d.ts +458 -0
- package/dist/src/layout/SpringElectricalLayoutEngine.d.ts +32 -0
- package/dist/src/layout/SpringLayoutEngine.d.ts +22 -32
- package/dist/src/managers/EventManager.d.ts +7 -0
- package/dist/src/managers/GraphContext.d.ts +6 -0
- package/dist/src/managers/LayoutManager.d.ts +98 -4
- package/dist/src/managers/RenderManager.d.ts +7 -0
- package/dist/src/managers/UpdateManager.d.ts +1 -1
- package/dist/src/session/catalog.d.ts +2 -2
- package/dist/src/session/query.d.ts +83 -0
- package/dist/src/session/runs/types.d.ts +10 -4
- package/dist/src/session/selection/targets.d.ts +20 -3
- package/dist/src/session/styles/StylesApi.d.ts +18 -0
- package/dist/src/session/styles/legend.d.ts +9 -0
- package/dist/src/session/styles/predicate.d.ts +11 -0
- package/dist/src/session/styles/sources.d.ts +16 -0
- package/dist/src/session/types.d.ts +38 -2
- package/dist/src/testing/fakeAccelerator.d.ts +323 -0
- package/dist/webgpu.d.ts +23 -1
- package/dist/webgpu.js +70 -32
- package/package.json +10 -8
- package/dist/chunks/types-Dwm9waL2.js +0 -7
|
@@ -1,42 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @file The Spring layout: Fruchterman-Reingold, computed on the CPU or on an accelerator.
|
|
3
|
+
*
|
|
4
|
+
* It used to be a one-shot pass -- run `springLayout` over a node and edge list, publish the
|
|
5
|
+
* answer, stop -- which is why the catalogue called it a batch layout. It is now a steppable
|
|
6
|
+
* simulation from `@graphty/layout`, so it keeps running until the arrangement settles and reheats
|
|
7
|
+
* on a drag or a pin, and the element decides at every load whether the simulation is the CPU's or
|
|
8
|
+
* the accelerator's.
|
|
9
|
+
*/
|
|
10
|
+
import type { SimulationType } from "@graphty/layout";
|
|
2
11
|
import { type OptionsSchema } from "../config";
|
|
3
|
-
import {
|
|
4
|
-
declare const SpringLayoutConfig: z.ZodObject<{
|
|
5
|
-
k: z.ZodDefault<z.ZodUnion<[z.ZodNumber, z.ZodNull]>>;
|
|
6
|
-
pos: z.ZodDefault<z.ZodUnion<[z.ZodRecord<z.ZodNumber, z.ZodArray<z.ZodNumber>>, z.ZodNull]>>;
|
|
7
|
-
fixed: z.ZodDefault<z.ZodUnion<[z.ZodArray<z.ZodNumber>, z.ZodNull]>>;
|
|
8
|
-
iterations: z.ZodDefault<z.ZodNumber>;
|
|
9
|
-
scale: z.ZodDefault<z.ZodNumber>;
|
|
10
|
-
center: z.ZodDefault<z.ZodUnion<[z.ZodArray<z.ZodNumber>, z.ZodNull]>>;
|
|
11
|
-
dim: z.ZodDefault<z.ZodNumber>;
|
|
12
|
-
seed: z.ZodDefault<z.ZodUnion<[z.ZodNumber, z.ZodNull]>>;
|
|
13
|
-
scalingFactor: z.ZodDefault<z.ZodNumber>;
|
|
14
|
-
}, z.core.$strict>;
|
|
15
|
-
type SpringLayoutConfigType = z.infer<typeof SpringLayoutConfig>;
|
|
16
|
-
type SpringLayoutOpts = Partial<SpringLayoutConfigType>;
|
|
12
|
+
import { SimulationLayoutEngine } from "./SimulationLayoutEngine";
|
|
17
13
|
/**
|
|
18
|
-
* Spring
|
|
14
|
+
* The Spring engine, as the element declares it.
|
|
15
|
+
*
|
|
16
|
+
* Every member is a static the element reads: `LayoutManager` builds the bridge itself, with the
|
|
17
|
+
* graph's acceleration controller, so this class never runs a layout of its own. It declares no
|
|
18
|
+
* `static descriptor` because its arrangement is authored in the layout catalogue, where it sits
|
|
19
|
+
* under `force`.
|
|
19
20
|
*/
|
|
20
|
-
export declare class SpringLayout extends
|
|
21
|
+
export declare class SpringLayout extends SimulationLayoutEngine {
|
|
21
22
|
static type: string;
|
|
23
|
+
static simulationType: SimulationType;
|
|
22
24
|
static maxDimensions: number;
|
|
23
25
|
static zodOptionsSchema: OptionsSchema;
|
|
24
|
-
scalingFactor: number;
|
|
25
|
-
config: SpringLayoutConfigType;
|
|
26
|
-
/**
|
|
27
|
-
* Create a spring layout engine
|
|
28
|
-
* @param opts - Configuration options including spring constant and iterations
|
|
29
|
-
*/
|
|
30
|
-
constructor(opts: SpringLayoutOpts);
|
|
31
26
|
/**
|
|
32
|
-
* Get dimension-specific options for spring layout
|
|
33
|
-
* @param dimension - The desired dimension (2 or 3)
|
|
34
|
-
* @returns Options object with dim parameter
|
|
27
|
+
* Get dimension-specific options for spring layout.
|
|
28
|
+
* @param dimension - The desired dimension (2 or 3).
|
|
29
|
+
* @returns Options object with dim parameter.
|
|
35
30
|
*/
|
|
36
31
|
static getOptionsForDimension(dimension: 2 | 3): object;
|
|
37
|
-
/**
|
|
38
|
-
* Compute node positions using spring-based force simulation
|
|
39
|
-
*/
|
|
40
|
-
doLayout(): void;
|
|
41
32
|
}
|
|
42
|
-
export {};
|
|
@@ -95,6 +95,13 @@ export declare class EventManager implements Manager {
|
|
|
95
95
|
* @param report - freezeWithReport's report
|
|
96
96
|
*/
|
|
97
97
|
emitSnapshotReplaced(graph: Graph | GraphContext, previous: GraphSnapshot | null, next: GraphSnapshot, report: FreezeReport): void;
|
|
98
|
+
/**
|
|
99
|
+
* Emit `snapshot-dropped`: the store was discarded and every snapshot it froze is gone.
|
|
100
|
+
*
|
|
101
|
+
* ELEMENT-INTERNAL, for the same reason `snapshot-replaced` is. Emitted while the outgoing
|
|
102
|
+
* store is still alive, so a listener releasing a snapshot can still derive from it.
|
|
103
|
+
*/
|
|
104
|
+
emitSnapshotDropped(): void;
|
|
98
105
|
/**
|
|
99
106
|
* Emits a layout initialized event when a layout is ready
|
|
100
107
|
* @param layoutType - Type of layout that was initialized
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Scene } from "@babylonjs/core";
|
|
2
|
+
import type { AccelerationController } from "../acceleration";
|
|
2
3
|
import type { XRConfig } from "../config/XRConfig";
|
|
3
4
|
import type { MeshCache } from "../meshes/MeshCache";
|
|
4
5
|
import type { Styles } from "../Styles";
|
|
@@ -92,6 +93,11 @@ export interface GraphContext {
|
|
|
92
93
|
* @since 1.5.0
|
|
93
94
|
*/
|
|
94
95
|
getEventManager?(): EventManager | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* The acceleration controller the graph owns; absent on a context built without a graph.
|
|
98
|
+
* @since 2.0.0
|
|
99
|
+
*/
|
|
100
|
+
getAcceleration?(): AccelerationController;
|
|
95
101
|
}
|
|
96
102
|
/**
|
|
97
103
|
* Configuration options accessible through GraphContext
|
|
@@ -1,11 +1,37 @@
|
|
|
1
|
+
import type { SimulationType } from "@graphty/layout";
|
|
2
|
+
import type { GraphLayoutBehavior } from "../config/GraphBehavior";
|
|
1
3
|
import type { Edge } from "../Edge";
|
|
2
4
|
import { LayoutEngine } from "../layout/LayoutEngine";
|
|
5
|
+
import { type SimulationEngineOptions } from "../layout/SimulationLayoutEngine";
|
|
3
6
|
import type { Node } from "../Node";
|
|
4
7
|
import type { Styles } from "../Styles";
|
|
5
8
|
import type { DataManager } from "./DataManager";
|
|
6
9
|
import type { EventManager } from "./EventManager";
|
|
7
10
|
import type { GraphContext } from "./GraphContext";
|
|
8
11
|
import type { Manager } from "./interfaces";
|
|
12
|
+
/**
|
|
13
|
+
* Turn what the consumer asked a simulation layout for into what the bridge runs on.
|
|
14
|
+
*
|
|
15
|
+
* `scalingFactor` travels twice over, and deliberately. The simulation gets it as `scale`, where
|
|
16
|
+
* it sizes the seed and, in ForceAtlas2, the units the arrangement is computed in; the BRIDGE gets
|
|
17
|
+
* it as the radius it publishes that arrangement at, which is the only one of the two a reader
|
|
18
|
+
* sees in the picture. A layout that publishes no such control takes
|
|
19
|
+
* {@link DEFAULT_SCALING_FACTOR}. What the bridge is given is {@link publishedRadius}, every
|
|
20
|
+
* size multiplier the layout publishes rolled into one, because the refit fits the arrangement to
|
|
21
|
+
* that radius and leaves no other way for a reader to change how big the graph comes out.
|
|
22
|
+
*
|
|
23
|
+
* The four knobs the frame loop needs -- `iterationsPerStep`, `maxInFlight`, `settleThreshold` and
|
|
24
|
+
* `settleWindow` -- are NOT in any layout's published schema, because they are the same four for
|
|
25
|
+
* every simulation and belong to how the element drives one rather than to the arrangement it
|
|
26
|
+
* draws. They are read from the options a caller passed, where a per-layout value overrides the
|
|
27
|
+
* behaviour configuration, and `behavior.layout` is where a host sets them once for every layout.
|
|
28
|
+
* @param type - Which simulation is being configured.
|
|
29
|
+
* @param options - The merged layout options, as the consumer set them.
|
|
30
|
+
* @param behavior - `behavior.layout`, which the frame-loop knobs default from.
|
|
31
|
+
* @returns The resolved options.
|
|
32
|
+
* @throws A `ZodError` when an option is outside the range its published schema declares.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveSimulationOptions(type: SimulationType, options: Record<string, unknown>, behavior: GraphLayoutBehavior): SimulationEngineOptions;
|
|
9
35
|
/**
|
|
10
36
|
* Manages layout engines and their lifecycle
|
|
11
37
|
* Coordinates layout updates and transitions
|
|
@@ -34,10 +60,27 @@ export declare class LayoutManager implements Manager {
|
|
|
34
60
|
*/
|
|
35
61
|
get running(): boolean;
|
|
36
62
|
/**
|
|
37
|
-
* Sets the running state of the layout
|
|
63
|
+
* Sets the running state of the layout.
|
|
64
|
+
*
|
|
65
|
+
* Going false -> true is "play", and a simulation that had SETTLED does nothing when it is
|
|
66
|
+
* stepped, so a reader who pressed play -- or let go of a node they dragged -- would watch a
|
|
67
|
+
* still graph. Resuming therefore reheats a settled simulation: the settle count starts
|
|
68
|
+
* again and the next frame moves nodes. Going true -> false only stops `step()` being
|
|
69
|
+
* called; batches already in flight land in the position array by themselves, nothing is
|
|
70
|
+
* disposed and nothing is released.
|
|
38
71
|
*/
|
|
39
72
|
set running(value: boolean);
|
|
40
73
|
private graphContext;
|
|
74
|
+
/**
|
|
75
|
+
* The graph's acceleration controller, once a context has arrived. A manager built without a
|
|
76
|
+
* graph -- which is what the manager's own unit tests build -- never gets one, and a
|
|
77
|
+
* simulation layout refuses to start on one.
|
|
78
|
+
*/
|
|
79
|
+
private acceleration;
|
|
80
|
+
/** How to stop listening to the controller. */
|
|
81
|
+
private unsubscribeAcceleration;
|
|
82
|
+
/** How to stop listening for a new snapshot. */
|
|
83
|
+
private unsubscribeSnapshot;
|
|
41
84
|
/**
|
|
42
85
|
* Creates an instance of LayoutManager
|
|
43
86
|
* @param eventManager - Event manager for emitting layout events
|
|
@@ -47,9 +90,33 @@ export declare class LayoutManager implements Manager {
|
|
|
47
90
|
constructor(eventManager: EventManager, dataManager: DataManager, styles: Styles);
|
|
48
91
|
/**
|
|
49
92
|
* Set the GraphContext for error reporting
|
|
93
|
+
*
|
|
94
|
+
* This is also where the acceleration controller first becomes reachable: the manager is
|
|
95
|
+
* built before the graph finishes constructing itself, so it cannot be handed one.
|
|
50
96
|
* @param context - GraphContext instance
|
|
51
97
|
*/
|
|
52
98
|
setGraphContext(context: GraphContext): void;
|
|
99
|
+
/**
|
|
100
|
+
* Rebuild a running simulation on whatever the controller holds now.
|
|
101
|
+
*
|
|
102
|
+
* Every transition reaches here: an accelerator attached, detached, lost or recovered. The
|
|
103
|
+
* try is load-bearing. Under the `required` policy a detach cannot reach a CPU simulation --
|
|
104
|
+
* the controller's `plan()` throws `E_NO_ACCELERATOR` instead, which is the point of the
|
|
105
|
+
* policy -- and the throw has to be REPORTED here rather than escaping into the controller's
|
|
106
|
+
* listener loop, whose own catch would log it and continue. The layout then stops, and the
|
|
107
|
+
* next transition that attaches an accelerator brings it back.
|
|
108
|
+
*/
|
|
109
|
+
private onAccelerationChange;
|
|
110
|
+
/**
|
|
111
|
+
* Hand a running simulation the snapshot that has just replaced the one it was laying out.
|
|
112
|
+
* @param event - The freeze, carrying the snapshot every consumer must switch to.
|
|
113
|
+
*/
|
|
114
|
+
private onSnapshotReplaced;
|
|
115
|
+
/**
|
|
116
|
+
* Report a failure that happened to a layout already running, on the element's error channel.
|
|
117
|
+
* @param error - Whatever was thrown.
|
|
118
|
+
*/
|
|
119
|
+
private reportSimulationFailure;
|
|
53
120
|
/**
|
|
54
121
|
* Update the styles reference when a new style template is loaded
|
|
55
122
|
* @param styles - New styles instance
|
|
@@ -103,6 +170,9 @@ export declare class LayoutManager implements Manager {
|
|
|
103
170
|
* @param type - The layout that failed.
|
|
104
171
|
* @param error - Whatever was thrown.
|
|
105
172
|
* @param phase - What the element was doing, in a word that fits "the layout could not be ...".
|
|
173
|
+
* `"stepped"` is the one that happens to a layout already running: a simulation's batch
|
|
174
|
+
* rejected minutes after set-up finished, and calling that "initialised" reads as a failure
|
|
175
|
+
* to start.
|
|
106
176
|
* @returns The error to throw.
|
|
107
177
|
*/
|
|
108
178
|
private reportLayoutFailure;
|
|
@@ -120,7 +190,19 @@ export declare class LayoutManager implements Manager {
|
|
|
120
190
|
* `preSteps` is what makes a screenshot of a physics layout the same picture twice: an
|
|
121
191
|
* unstepped force layout is a graph in mid-flight, and how far it has flown depends on when
|
|
122
192
|
* the picture was taken.
|
|
193
|
+
*
|
|
194
|
+
* A SIMULATION CANNOT BE STEPPED IN A TIGHT SYNCHRONOUS LOOP, which is why this is
|
|
195
|
+
* asynchronous and why both the path that spends the pre-steps when a layout is built and the
|
|
196
|
+
* path that pays owed ones later come through here rather than each writing their own loop. A
|
|
197
|
+
* simulation's step is a BATCH: an accelerated one is fire-and-forget, and a simulation that
|
|
198
|
+
* already has a few batches in flight returns the oldest of them instead of submitting
|
|
199
|
+
* another, so a loop that calls `step()` a thousand times without waiting has all but the
|
|
200
|
+
* first couple coalesced away and draws a graph the consumer asked to be far more arranged
|
|
201
|
+
* than it is -- silently, because a coalesced batch is not an error. So a simulation is
|
|
202
|
+
* awaited one chunk at a time, the chunk being the largest batch the GPU package takes, and
|
|
203
|
+
* every other engine keeps the plain loop, whose `step()` returns having done the work.
|
|
123
204
|
* @param engine - the engine to settle.
|
|
205
|
+
* @returns A promise that resolves once every pre-step has been taken and published.
|
|
124
206
|
*/
|
|
125
207
|
private spendPreSteps;
|
|
126
208
|
/**
|
|
@@ -136,15 +218,27 @@ export declare class LayoutManager implements Manager {
|
|
|
136
218
|
*
|
|
137
219
|
* So the count is owed rather than spent, and paid here: on the first frame at which there is
|
|
138
220
|
* a node to move. This runs inside the render loop's update, which is called before
|
|
139
|
-
* `scene.render()`, so
|
|
140
|
-
* waits for a node rather than for a particular call, it does not
|
|
141
|
-
* arrived in one batch, in ten, or from a fetch that finished a
|
|
221
|
+
* `scene.render()`, so an engine that steps on the spot really is stepped before the frame is
|
|
222
|
+
* drawn -- and because it waits for a node rather than for a particular call, it does not
|
|
223
|
+
* matter whether the data arrived in one batch, in ten, or from a fetch that finished a
|
|
224
|
+
* second later. A simulation's batches land over the next few frames instead, because no
|
|
225
|
+
* caller inside a render loop can wait for a device; what {@link LayoutManager.spendPreSteps}
|
|
226
|
+
* guarantees for one is that every owed iteration is computed rather than coalesced away.
|
|
142
227
|
*/
|
|
143
228
|
private runPreStepsOnceThereIsSomethingToStep;
|
|
144
229
|
/**
|
|
145
230
|
* Step the layout engine forward
|
|
146
231
|
*/
|
|
147
232
|
step(): void;
|
|
233
|
+
/**
|
|
234
|
+
* Step the layout ONCE, whatever the frame loop's multiplier is.
|
|
235
|
+
*
|
|
236
|
+
* The name is the difference a reader of `UpdateManager` needs: a simulation layout does its
|
|
237
|
+
* whole frame's work in one call -- the batch it submits computes `iterationsPerStep`
|
|
238
|
+
* iterations -- so stepping it `stepMultiplier` times a frame would queue work the device
|
|
239
|
+
* cannot retire.
|
|
240
|
+
*/
|
|
241
|
+
stepBatch(): void;
|
|
148
242
|
/**
|
|
149
243
|
* Get node position from layout engine
|
|
150
244
|
* @param node - Node to get position for
|
|
@@ -23,6 +23,13 @@ export declare class RenderManager implements Manager {
|
|
|
23
23
|
private renderLoopActive;
|
|
24
24
|
private updateCallback?;
|
|
25
25
|
private resizeHandler;
|
|
26
|
+
/**
|
|
27
|
+
* Stands in for Babylon's own pointer handling, which calls preventDefault and then
|
|
28
|
+
* `canvas.focus()` on every pointer down and up. That focus call scrolls the host page to the
|
|
29
|
+
* canvas. This one does the same thing without scrolling.
|
|
30
|
+
* @param evt - The pointer down or up event on the canvas
|
|
31
|
+
*/
|
|
32
|
+
private focusOnPointer;
|
|
26
33
|
/**
|
|
27
34
|
* Creates a new render manager for Babylon.js scene and rendering
|
|
28
35
|
* @param canvas - HTML canvas element for rendering
|
|
@@ -330,7 +330,7 @@ export declare class UpdateManager implements Manager {
|
|
|
330
330
|
/**
|
|
331
331
|
* Update the graph for the current frame.
|
|
332
332
|
*
|
|
333
|
-
* The pass itself is
|
|
333
|
+
* The pass itself is the private `runUpdatePass()`; what is added here is the one
|
|
334
334
|
* question a consumer cares about and the pass has several exits from -- whether the state it
|
|
335
335
|
* leaves behind is a finished picture.
|
|
336
336
|
*/
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
* already been run here. So a session's catalogue is the shared tables with its own `metrics()`
|
|
30
30
|
* closed over its own graph.
|
|
31
31
|
*
|
|
32
|
-
* The rest of the graph-dependent half -- resolved option bounds, expression validation --
|
|
33
|
-
*
|
|
32
|
+
* The rest of the graph-dependent half -- resolved option bounds, expression validation -- is not
|
|
33
|
+
* wired to the session's query engine yet.
|
|
34
34
|
*/
|
|
35
35
|
import type { AlgorithmDescriptor } from "../catalog/types";
|
|
36
36
|
import { type MetricsSource } from "./metrics";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The session's one query engine: `{ where }` predicates and text search.
|
|
3
|
+
*
|
|
4
|
+
* A scope, a selection, a visibility filter and an edge filter all accept an expression, and a
|
|
5
|
+
* selection also accepts typed text. Every one of them reaches THIS object, and this object
|
|
6
|
+
* evaluates an expression with the compiler the style layers use (`./styles/predicate`) over the
|
|
7
|
+
* selector source the style layers read (`./styles/sources`). That is the point of it: a layer
|
|
8
|
+
* selector and a scope with the same text match the same elements, because they are the same
|
|
9
|
+
* code reading the same values. A second evaluator would drift from the first in exactly the
|
|
10
|
+
* places nobody tests -- JMESPath truthiness, a column default, an edge's endpoints.
|
|
11
|
+
*
|
|
12
|
+
* A path nothing answers matches nothing and is REPORTED through `unresolvedPathsOf`, never
|
|
13
|
+
* swallowed: "0 matched" and "you misspelled the attribute" must not look the same.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here reaches Babylon.js, Lit or the DOM.
|
|
16
|
+
*/
|
|
17
|
+
import type { GraphSnapshot } from "@graphty/graph-format";
|
|
18
|
+
import type { EdgeId, NodeId, Path, Query } from "../catalog/types";
|
|
19
|
+
import type { SelectionMatch, SelectionSearchHit, SelectionTextMode } from "./selection";
|
|
20
|
+
import { type SelectorSource, type SelectorTarget } from "./styles/predicate";
|
|
21
|
+
/** Everything the engine reads. */
|
|
22
|
+
interface QueryEngineParts {
|
|
23
|
+
/**
|
|
24
|
+
* The snapshot the dense indices address, read on every query.
|
|
25
|
+
* @returns The snapshot as it stands now.
|
|
26
|
+
*/
|
|
27
|
+
readonly snapshot: () => GraphSnapshot;
|
|
28
|
+
/** Where values are read: the same source the style layers read. */
|
|
29
|
+
readonly elements: Required<Pick<SelectorSource, "edgeIdOf" | "nodeIdOf">> & SelectorSource;
|
|
30
|
+
/**
|
|
31
|
+
* Whether this session answers a path for one kind of element. Absent, no path is reported.
|
|
32
|
+
* @param path - The path as the query spelled it.
|
|
33
|
+
* @param target - Which kind of element.
|
|
34
|
+
* @returns True when something in the session answers it.
|
|
35
|
+
*/
|
|
36
|
+
readonly answers?: (path: Path, target: SelectorTarget) => boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The node attribute paths a text search reads, beside the id.
|
|
39
|
+
* @returns The paths, such as `data.label`.
|
|
40
|
+
*/
|
|
41
|
+
readonly searchPaths: () => readonly Path[];
|
|
42
|
+
}
|
|
43
|
+
/** The session's query engine. */
|
|
44
|
+
export interface QueryEngine {
|
|
45
|
+
/**
|
|
46
|
+
* The nodes an expression matches.
|
|
47
|
+
* @param where - The expression.
|
|
48
|
+
* @returns The node ids, in index order.
|
|
49
|
+
*/
|
|
50
|
+
nodes(where: Query): NodeId[];
|
|
51
|
+
/**
|
|
52
|
+
* The edges an expression matches.
|
|
53
|
+
* @param where - The expression.
|
|
54
|
+
* @returns The edge ids, in index order.
|
|
55
|
+
*/
|
|
56
|
+
edges(where: Query): EdgeId[];
|
|
57
|
+
/**
|
|
58
|
+
* Both halves an expression matches, and the paths it names that nothing answers.
|
|
59
|
+
* @param where - The expression.
|
|
60
|
+
* @returns The match.
|
|
61
|
+
*/
|
|
62
|
+
select(where: Query): SelectionMatch;
|
|
63
|
+
/**
|
|
64
|
+
* The paths an expression names that no node and no edge in this session answers.
|
|
65
|
+
* @param where - The expression.
|
|
66
|
+
* @returns The unresolved paths.
|
|
67
|
+
*/
|
|
68
|
+
unresolvedPathsOf(where: Query): readonly Path[];
|
|
69
|
+
/**
|
|
70
|
+
* The nodes a text search finds.
|
|
71
|
+
* @param text - What was typed.
|
|
72
|
+
* @param mode - How to match it.
|
|
73
|
+
* @returns The hits, in index order.
|
|
74
|
+
*/
|
|
75
|
+
find(text: string, mode: SelectionTextMode): SelectionSearchHit[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the query engine over a session's selector source.
|
|
79
|
+
* @param parts - The snapshot, the value source, the path directory and the searchable paths.
|
|
80
|
+
* @returns The engine.
|
|
81
|
+
*/
|
|
82
|
+
export declare function createQueryEngine(parts: QueryEngineParts): QueryEngine;
|
|
83
|
+
export {};
|
|
@@ -465,10 +465,16 @@ export interface Run<T = RunResult> extends PromiseLike<T> {
|
|
|
465
465
|
readonly shape: ResultShape;
|
|
466
466
|
/** What qualifies the numbers. */
|
|
467
467
|
readonly caveats: Caveats;
|
|
468
|
-
/**
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
468
|
+
/**
|
|
469
|
+
* The result, once there is one. Awaiting the run is the other way to get it.
|
|
470
|
+
*
|
|
471
|
+
* Spelled `?: T | undefined` rather than `?: T` because the implementation answers with a
|
|
472
|
+
* getter, and under a consumer's `exactOptionalPropertyTypes` a getter that can return
|
|
473
|
+
* undefined does not satisfy a property that can only be absent or present.
|
|
474
|
+
*/
|
|
475
|
+
readonly result?: T | undefined;
|
|
476
|
+
/** Why it failed, when it failed. Optional-or-undefined for the reason {@link Run.result} gives. */
|
|
477
|
+
readonly error?: GraphtyError | undefined;
|
|
472
478
|
/** The frozen, structured-cloneable snapshot of everything above. */
|
|
473
479
|
readonly record: RunRecord;
|
|
474
480
|
/** The journal entry this run's command wrote, or null until it lands. */
|
|
@@ -32,7 +32,15 @@ import type { EdgeId, NodeId, Path, Query, Scope } from "../../catalog/types";
|
|
|
32
32
|
import type { ResultsApi, RunRef } from "../results/types";
|
|
33
33
|
import { ElementMask, type MaskIdSpace } from "../scope/ElementMask";
|
|
34
34
|
import type { ScopeResolver } from "../scope/ScopeApi";
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* How a text target decides whether an element matched.
|
|
37
|
+
*
|
|
38
|
+
* - `substring`: the id or an attribute value contains the text, ignoring case.
|
|
39
|
+
* - `exact`: the id or an attribute value is the text, exactly.
|
|
40
|
+
* - `regex`: the id or an attribute value matches the text as a regular expression.
|
|
41
|
+
* - `attribute`: the text is `key:value`, and the node's `key` (or its id, for `id`) is the value,
|
|
42
|
+
* ignoring case. A key no node carries is searched as plain substring text.
|
|
43
|
+
*/
|
|
36
44
|
export type SelectionTextMode = "substring" | "exact" | "regex" | "attribute";
|
|
37
45
|
/** Which way a neighbourhood target follows an edge. */
|
|
38
46
|
export type SelectionDirection = "in" | "out" | "all";
|
|
@@ -70,14 +78,23 @@ export interface NeighborhoodTarget {
|
|
|
70
78
|
* second ranking that could disagree with the one on screen.
|
|
71
79
|
*/
|
|
72
80
|
export type SelectionTarget = ElementIdTarget | NeighborhoodTarget
|
|
73
|
-
/** Every element a predicate matches. */
|
|
81
|
+
/** Every element a predicate matches, narrowed to a scope when one is named. */
|
|
74
82
|
| {
|
|
75
83
|
readonly where: Query;
|
|
84
|
+
readonly scope?: Scope;
|
|
76
85
|
}
|
|
77
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* Every node a text search finds, narrowed to a scope when one is named.
|
|
88
|
+
*
|
|
89
|
+
* With no `mode`, the text may carry one as a prefix: `exact:`, `regex:`, or `<attribute>:`
|
|
90
|
+
* (`id:a17`, `type:person`), and anything else is a case-insensitive substring search over
|
|
91
|
+
* the node's id and its attribute values. See {@link SelectionTextMode}. A leading `=` makes
|
|
92
|
+
* the rest an expression, exactly as `{ where }` reads it, which selects edges as well.
|
|
93
|
+
*/
|
|
78
94
|
| {
|
|
79
95
|
readonly text: string;
|
|
80
96
|
readonly mode?: SelectionTextMode;
|
|
97
|
+
readonly scope?: Scope;
|
|
81
98
|
}
|
|
82
99
|
/** A pasted list of ids, which may name nodes, edges, or nothing at all. */
|
|
83
100
|
| {
|
|
@@ -494,6 +494,24 @@ export interface StylesSources {
|
|
|
494
494
|
*/
|
|
495
495
|
readonly onChange?: (change: StyleChange) => void;
|
|
496
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* What a highlight paints when its caller names no style.
|
|
499
|
+
*
|
|
500
|
+
* A highlight is drawn OVER the default indigo node, the default darkgrey edge and the whitesmoke
|
|
501
|
+
* background, so it is chosen against those three rather than on its own. Okabe-Ito vermilion is
|
|
502
|
+
* at least Delta E 16 from each of them at normal vision and under all three kinds of colour
|
|
503
|
+
* blindness, and 3.5:1 against the background. The blue this replaced was Delta E 13 from the
|
|
504
|
+
* default node and under 4 for tritanopia, so a route through default nodes disappeared into
|
|
505
|
+
* them. `test/catalog/default-palette-quality.test.ts` measures it.
|
|
506
|
+
*
|
|
507
|
+
* Colour alone is not enough for an edge: a thin line at the default width reads as a thin line
|
|
508
|
+
* whatever its colour, so a highlighted edge is also drawn three times as wide. A node gets no
|
|
509
|
+
* size, because a size here would flatten whatever size encoding the layers beneath it drew.
|
|
510
|
+
*/
|
|
511
|
+
export declare const DEFAULT_HIGHLIGHT: {
|
|
512
|
+
readonly color: "#D55E00";
|
|
513
|
+
readonly edgeWidth: number;
|
|
514
|
+
};
|
|
497
515
|
/**
|
|
498
516
|
* Build the style stack one session holds.
|
|
499
517
|
* @param sources - What a selector compiles against, the element's own layers, the scales, the
|
|
@@ -184,6 +184,15 @@ export interface LegendSources {
|
|
|
184
184
|
* @returns The words, or undefined when nothing in the session names that path.
|
|
185
185
|
*/
|
|
186
186
|
readonly field?: (path: Path, target: SelectorTarget) => FieldWords | undefined;
|
|
187
|
+
/**
|
|
188
|
+
* Whether a layer above selects every element a layer below it selects.
|
|
189
|
+
*
|
|
190
|
+
* Absent, only a layer that selects everything is known to cover one below it.
|
|
191
|
+
* @param above - The higher layer.
|
|
192
|
+
* @param below - The lower layer.
|
|
193
|
+
* @returns True only when every element `below` selects is also selected by `above`.
|
|
194
|
+
*/
|
|
195
|
+
readonly covers?: (above: Layer, below: Layer) => boolean;
|
|
187
196
|
}
|
|
188
197
|
/**
|
|
189
198
|
* Read the legend out of the encoding model.
|
|
@@ -104,6 +104,17 @@ export interface SelectorSource {
|
|
|
104
104
|
* @returns The id at that row.
|
|
105
105
|
*/
|
|
106
106
|
readonly edgeIdOf?: (index: number) => EdgeId;
|
|
107
|
+
/**
|
|
108
|
+
* The dense indices that carry a value for one column, ascending, when the source can list
|
|
109
|
+
* them without a walk over every element. A session answers it for a run's column.
|
|
110
|
+
*
|
|
111
|
+
* Absent, or answering undefined, nothing asks the question another way: the legend then
|
|
112
|
+
* reports a layer as painted over only by a layer that selects everything.
|
|
113
|
+
* @param path - The column path.
|
|
114
|
+
* @param target - Whether the asking layer paints nodes or edges.
|
|
115
|
+
* @returns The indices, or undefined when the column cannot be enumerated.
|
|
116
|
+
*/
|
|
117
|
+
readonly measured?: (path: Path, target: SelectorTarget) => ArrayLike<number> | undefined;
|
|
107
118
|
}
|
|
108
119
|
/**
|
|
109
120
|
* One target's half of a {@link SelectorSource}, resolved once so the predicate never chooses.
|
|
@@ -132,6 +132,22 @@ export interface SessionSelectorSource extends SelectorSource {
|
|
|
132
132
|
*/
|
|
133
133
|
readonly measured: (path: Path, target: SelectorTarget) => ArrayLike<number> | undefined;
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The id of the node at one end of an edge, for the attribute keys that name an endpoint.
|
|
137
|
+
*
|
|
138
|
+
* An edge's endpoints are graph structure, so the importer removes the keys they arrived under
|
|
139
|
+
* (`src`/`dst`, or whatever the id paths name) from the record a selector reads, to keep the data
|
|
140
|
+
* table from showing them twice. Without this, `data.source == 'A'` matched no edge at all and
|
|
141
|
+
* said nothing -- the empty answer looked exactly like a correct zero. So `source` and `target`
|
|
142
|
+
* are read from the snapshot for an edge whose record holds nothing under that key; an edge that
|
|
143
|
+
* really carries a `source` attribute (a provenance field, with its endpoints under `src`/`dst`)
|
|
144
|
+
* keeps it.
|
|
145
|
+
* @param graph - The snapshot the index addresses.
|
|
146
|
+
* @param index - The dense (logical) edge index, already bounded by the caller.
|
|
147
|
+
* @param key - The attribute key, without the `data.` prefix.
|
|
148
|
+
* @returns The endpoint's node id, or undefined when the key names no endpoint.
|
|
149
|
+
*/
|
|
150
|
+
export declare function edgeEndpointOf(graph: GraphSnapshot, index: number, key: string): NodeId | undefined;
|
|
135
151
|
/**
|
|
136
152
|
* Build the selector source for one session.
|
|
137
153
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { DerivedGraph, GraphSnapshot, NodeId } from "@graphty/graph-format";
|
|
16
16
|
import type { z } from "zod/v4";
|
|
17
|
-
import type { AccelerationCapabilities, AccelerationPolicy } from "../acceleration";
|
|
17
|
+
import type { AccelerationCapabilities, AccelerationPolicy, AccelerationStatus, GraphAccelerator } from "../acceleration";
|
|
18
18
|
import type { AlgorithmKey, AttributeDescriptor, CatalogApi, EdgeId, RunId, Scope } from "../catalog/types";
|
|
19
19
|
import type { DataConfig } from "../config/DataConfig";
|
|
20
20
|
import type { ElementPositions } from "../data/positions";
|
|
@@ -349,7 +349,7 @@ export interface SessionDataApi {
|
|
|
349
349
|
*
|
|
350
350
|
* The rest of the graph-dependent half of {@link CatalogApi} -- what an option's bounds resolve to
|
|
351
351
|
* over a scope, whether an expression references anything real -- is still absent rather than
|
|
352
|
-
* stubbed
|
|
352
|
+
* stubbed: the session's query engine exists, and the catalogue is not wired to it yet. A consumer discovers that gap by
|
|
353
353
|
* autocomplete finding nothing, not by a call that throws.
|
|
354
354
|
*/
|
|
355
355
|
export type SessionCatalogApi = Pick<CatalogApi, "algorithms" | "cameras" | "formats" | "layouts" | "logSinks" | "metrics" | "palettes" | "scales">;
|
|
@@ -409,6 +409,10 @@ export interface SessionEventMap {
|
|
|
409
409
|
* looking at an old picture that reads as an answer.
|
|
410
410
|
*/
|
|
411
411
|
"style:problem": StyleProblem;
|
|
412
|
+
/** Every acceleration transition; the document is the one `capabilities` returns. */
|
|
413
|
+
"capabilities:changed": {
|
|
414
|
+
readonly capabilities: AccelerationCapabilities;
|
|
415
|
+
};
|
|
412
416
|
}
|
|
413
417
|
/**
|
|
414
418
|
* A painting the element started for itself, and why it did not land.
|
|
@@ -500,6 +504,22 @@ export interface GraphSession {
|
|
|
500
504
|
readonly config: SessionConfig;
|
|
501
505
|
/** What this machine can do, measured rather than guessed at by the consumer. */
|
|
502
506
|
readonly capabilities: AccelerationCapabilities;
|
|
507
|
+
/**
|
|
508
|
+
* What the consumer asks of the hardware: use an accelerator when there is one, never look,
|
|
509
|
+
* or refuse to run without one.
|
|
510
|
+
*
|
|
511
|
+
* Settable, and the set applies at once: the next piece of accelerated work is planned under
|
|
512
|
+
* the new policy, and `capabilities:changed` reports where that left the hardware.
|
|
513
|
+
*/
|
|
514
|
+
acceleration: AccelerationPolicy;
|
|
515
|
+
/**
|
|
516
|
+
* Attach an accelerator the caller built, or detach the current one with `null`.
|
|
517
|
+
*
|
|
518
|
+
* For tests and third parties. An injected accelerator is never replaced by a probed one and
|
|
519
|
+
* is not disposed by the session -- whoever built it owns its lifetime.
|
|
520
|
+
* @param accelerator - The accelerator to attach, or null to detach.
|
|
521
|
+
*/
|
|
522
|
+
setAccelerator(accelerator: GraphAccelerator | null): void;
|
|
503
523
|
/**
|
|
504
524
|
* The current snapshot, by reference: nothing is copied.
|
|
505
525
|
* @returns the immutable graph-format snapshot
|
|
@@ -665,6 +685,22 @@ export interface AccelerationControllerLike {
|
|
|
665
685
|
readonly policy: AccelerationPolicy;
|
|
666
686
|
/** The node count at or above which accelerated work uses the accelerator. */
|
|
667
687
|
readonly minNodes: number;
|
|
688
|
+
/**
|
|
689
|
+
* Changes what the consumer asks of the hardware.
|
|
690
|
+
* @param policy - The new policy.
|
|
691
|
+
*/
|
|
692
|
+
setPolicy(policy: AccelerationPolicy): void;
|
|
693
|
+
/**
|
|
694
|
+
* Attaches an accelerator the caller built, or detaches the current one with `null`.
|
|
695
|
+
* @param accelerator - The accelerator, or null to detach.
|
|
696
|
+
*/
|
|
697
|
+
setAccelerator(accelerator: GraphAccelerator | null): void;
|
|
698
|
+
/**
|
|
699
|
+
* Watches every transition.
|
|
700
|
+
* @param listener - Called with the new status.
|
|
701
|
+
* @returns A function that stops the subscription.
|
|
702
|
+
*/
|
|
703
|
+
onChange(listener: (status: AccelerationStatus) => void): () => void;
|
|
668
704
|
/** Releases the hardware. */
|
|
669
705
|
dispose(): void;
|
|
670
706
|
}
|