@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,56 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @file The ForceAtlas2 layout: the Gephi arrangement, computed on the CPU or on an accelerator.
|
|
3
|
+
*
|
|
4
|
+
* It used to be a one-shot pass -- run `forceatlas2Layout` 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 ForceAtlas2LayoutConfig: z.ZodObject<{
|
|
5
|
-
pos: z.ZodDefault<z.ZodUnion<[z.ZodRecord<z.ZodNumber, z.ZodArray<z.ZodNumber>>, z.ZodNull]>>;
|
|
6
|
-
maxIter: z.ZodDefault<z.ZodNumber>;
|
|
7
|
-
jitterTolerance: z.ZodDefault<z.ZodNumber>;
|
|
8
|
-
scalingRatio: z.ZodDefault<z.ZodNumber>;
|
|
9
|
-
gravity: z.ZodDefault<z.ZodNumber>;
|
|
10
|
-
distributedAction: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
-
strongGravity: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
-
nodeMass: z.ZodDefault<z.ZodUnion<[z.ZodRecord<z.ZodNumber, z.ZodNumber>, z.ZodNull]>>;
|
|
13
|
-
nodeSize: z.ZodDefault<z.ZodUnion<[z.ZodRecord<z.ZodNumber, z.ZodNumber>, z.ZodNull]>>;
|
|
14
|
-
weighted: z.ZodDefault<z.ZodBoolean>;
|
|
15
|
-
dissuadeHubs: z.ZodDefault<z.ZodBoolean>;
|
|
16
|
-
linlog: z.ZodDefault<z.ZodBoolean>;
|
|
17
|
-
seed: z.ZodDefault<z.ZodUnion<[z.ZodNumber, z.ZodNull]>>;
|
|
18
|
-
dim: z.ZodDefault<z.ZodNumber>;
|
|
19
|
-
scalingFactor: z.ZodDefault<z.ZodNumber>;
|
|
20
|
-
}, z.core.$strict>;
|
|
21
|
-
type ForceAtlas2LayoutConfigType = z.infer<typeof ForceAtlas2LayoutConfig>;
|
|
22
|
-
type ForceAtlas2LayoutOpts = Partial<ForceAtlas2LayoutConfigType>;
|
|
12
|
+
import { SimulationLayoutEngine } from "./SimulationLayoutEngine";
|
|
23
13
|
/**
|
|
24
|
-
* ForceAtlas2
|
|
14
|
+
* The ForceAtlas2 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`.
|
|
25
20
|
*/
|
|
26
|
-
export declare class ForceAtlas2Layout extends
|
|
21
|
+
export declare class ForceAtlas2Layout extends SimulationLayoutEngine {
|
|
27
22
|
static type: string;
|
|
23
|
+
static simulationType: SimulationType;
|
|
28
24
|
static maxDimensions: number;
|
|
29
|
-
static honoursWeights: boolean;
|
|
30
|
-
static zodOptionsSchema: OptionsSchema;
|
|
31
|
-
scalingFactor: number;
|
|
32
|
-
config: ForceAtlas2LayoutConfigType;
|
|
33
25
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
26
|
+
* A WEIGHT IS AN ATTRACTION STRENGTH HERE, and is passed through as it is stored: a heavier
|
|
27
|
+
* edge pulls its two nodes closer, which is what a weight means everywhere else in the
|
|
28
|
+
* element. Kamada-Kawai reads the very same number as a distance and therefore inverts it; the
|
|
29
|
+
* two engines disagree about the arithmetic so that they agree about the meaning.
|
|
36
30
|
*/
|
|
37
|
-
|
|
31
|
+
static honoursWeights: boolean;
|
|
32
|
+
static zodOptionsSchema: OptionsSchema;
|
|
38
33
|
/**
|
|
39
|
-
* Get dimension-specific options for ForceAtlas2 layout
|
|
40
|
-
* @param dimension - The desired dimension (2 or 3)
|
|
41
|
-
* @returns Options object with dim parameter
|
|
34
|
+
* Get dimension-specific options for ForceAtlas2 layout.
|
|
35
|
+
* @param dimension - The desired dimension (2 or 3).
|
|
36
|
+
* @returns Options object with dim parameter.
|
|
42
37
|
*/
|
|
43
38
|
static getOptionsForDimension(dimension: 2 | 3): object;
|
|
44
|
-
/**
|
|
45
|
-
* Compute node positions using the ForceAtlas2 algorithm
|
|
46
|
-
*
|
|
47
|
-
* A WEIGHT IS PASSED THROUGH AS IT IS STORED. ForceAtlas2 reads a weight as an attraction
|
|
48
|
-
* STRENGTH -- it becomes the adjacency matrix entry the attraction force is scaled by -- which
|
|
49
|
-
* is already what a weight means everywhere else in the element, so a heavier edge pulls its
|
|
50
|
-
* two nodes closer and nothing has to be inverted. Kamada-Kawai reads the very same number as
|
|
51
|
-
* a distance and therefore does invert it; the two engines disagree about the arithmetic so
|
|
52
|
-
* that they agree about the meaning.
|
|
53
|
-
*/
|
|
54
|
-
doLayout(): void;
|
|
55
39
|
}
|
|
56
|
-
export {};
|
|
@@ -48,15 +48,15 @@ export interface LayoutEngineStatics {
|
|
|
48
48
|
/**
|
|
49
49
|
* Whether this engine arranges a graph differently when its edges carry weights.
|
|
50
50
|
*
|
|
51
|
-
* Optional, and false for all but two of the element's own
|
|
51
|
+
* Optional, and false for all but two of the element's own seventeen. It exists so that a
|
|
52
52
|
* picker can tell a reader which arrangements the `weighted` option actually does something
|
|
53
|
-
* for, instead of offering it on
|
|
53
|
+
* for, instead of offering it on fifteen layouts that ignore it.
|
|
54
54
|
*/
|
|
55
55
|
honoursWeights?: boolean;
|
|
56
56
|
/**
|
|
57
57
|
* What the catalogue publishes about this layout, so a picker can offer it.
|
|
58
58
|
*
|
|
59
|
-
* REQUIRED OF A THIRD PARTY'S ENGINE and absent from the element's own
|
|
59
|
+
* REQUIRED OF A THIRD PARTY'S ENGINE and absent from the element's own seventeen, whose
|
|
60
60
|
* arrangements are authored in `src/catalog/layouts.ts` instead. `descriptor.id` must equal
|
|
61
61
|
* {@link LayoutEngineStatics.type}: one key, so nothing is named twice and `layoutIdForEngine`
|
|
62
62
|
* can answer a plugin's own id.
|
|
@@ -94,7 +94,7 @@ export declare abstract class LayoutEngine {
|
|
|
94
94
|
* Whether this engine reads edge weights. See {@link LayoutEngineStatics.honoursWeights}.
|
|
95
95
|
*
|
|
96
96
|
* False here because most layouts have no weight channel at all: of the element's own
|
|
97
|
-
*
|
|
97
|
+
* seventeen, only Kamada-Kawai and ForceAtlas2 can read one, and the other fifteen would be
|
|
98
98
|
* advertising a control that changes nothing.
|
|
99
99
|
*/
|
|
100
100
|
static honoursWeights: boolean;
|
|
@@ -162,7 +162,7 @@ export declare abstract class LayoutEngine {
|
|
|
162
162
|
* Take a node out of the layout, before the element disposes the mesh that drew it.
|
|
163
163
|
*
|
|
164
164
|
* Declared here, with a default that does nothing, because it used to be duck-typed by the
|
|
165
|
-
* element's data manager and implemented by none of the
|
|
165
|
+
* element's data manager and implemented by none of the seventeen engines that ship here: an
|
|
166
166
|
* author learned it existed by reading the element's source, and got no worked example. An
|
|
167
167
|
* engine that keeps its own node list must override this, or it holds every removed node --
|
|
168
168
|
* and everything that node references -- for as long as the engine lives.
|
|
@@ -260,7 +260,7 @@ export declare abstract class LayoutEngine {
|
|
|
260
260
|
* freeze counts as placed, which is what makes a file's own coordinates yield to it.
|
|
261
261
|
*
|
|
262
262
|
* A PINNED ROW REFUSES A LAYOUT STEP. This is the whole of "a pin is meaningful under every
|
|
263
|
-
* arrangement":
|
|
263
|
+
* arrangement": twelve of the element's seventeen engines implement `pin()` as a no-op and
|
|
264
264
|
* `setNodePosition` as a no-op too, so before this guard a reader who dragged a node under a
|
|
265
265
|
* static layout watched it snap back the next time the layout recomputed. One refusal here
|
|
266
266
|
* covers every engine, including one written by a third party that has never heard of pinning,
|
|
@@ -351,7 +351,7 @@ export declare abstract class LayoutEngine {
|
|
|
351
351
|
* offered by a picker, described in a reader's language, or found by `layoutIdForEngine`.
|
|
352
352
|
*
|
|
353
353
|
* A third party's class must declare a `static descriptor` whose `id` equals its
|
|
354
|
-
* `static type`. The element's own
|
|
354
|
+
* `static type`. The element's own seventeen are the one exemption, because their arrangements
|
|
355
355
|
* are authored centrally in the layout catalogue where several engines may sit behind one
|
|
356
356
|
* public name.
|
|
357
357
|
* @param cls - The layout engine class.
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The layout bridge: one `LayoutEngine` driving `@graphty/layout`'s `LayoutSimulation`,
|
|
3
|
+
* on the CPU or on whatever the element's acceleration controller has attached.
|
|
4
|
+
*
|
|
5
|
+
* WHERE THE DECISION IS TAKEN. "GPU or CPU" is asked of the controller ONCE per simulation, by
|
|
6
|
+
* `plan({ capability, nodeCount })`, before any work starts -- at the first load, at every
|
|
7
|
+
* reload (a freeze can cross the `acceleration.minNodes` threshold in either direction) and at
|
|
8
|
+
* every swap. Nothing inside a running batch may change the answer: a rejected batch is
|
|
9
|
+
* reported with its own code and stops the stepping, and only the controller's NEXT transition
|
|
10
|
+
* -- a recovery, a detach, an injection -- rebuilds the simulation, through
|
|
11
|
+
* {@link SimulationLayoutEngine.replaceSimulation}. That is the difference between capability
|
|
12
|
+
* detection, which is required, and a silent CPU fallback after a GPU failure, which is not.
|
|
13
|
+
*
|
|
14
|
+
* TWO ARRAYS, TWO UNIT SYSTEMS. The simulations are the only layouts in this element that never
|
|
15
|
+
* rescale what they compute: a ForceAtlas2 equilibrium grows with the graph, so a settled
|
|
16
|
+
* hundred-node arrangement is a few hundred units across and a settled fifty-thousand-node one is
|
|
17
|
+
* tens of thousands, while every visual size in the element -- node size, edge width, label size,
|
|
18
|
+
* arrow size -- is an absolute scene unit tuned for the plus-or-minus-100 box the one-shot engines
|
|
19
|
+
* publish into. So the simulation is given an array of ITS OWN, and `publishPositions()` maps it
|
|
20
|
+
* into the element's: the widest radius about its own centre, over the rows that publish actually
|
|
21
|
+
* writes, becomes `scalingFactor`, recomputed at every publish so a settling graph holds its
|
|
22
|
+
* apparent size instead of flying out of frame. Everything written the other way -- a drag, a pin replay, a
|
|
23
|
+
* `setNodePosition`, the seed -- arrives in scene units and is divided back out, so a dragged node
|
|
24
|
+
* lands under the pointer. The simulation's own settle rule, trace and statistics never see any of
|
|
25
|
+
* this: they are computed in its units, and its units do not move.
|
|
26
|
+
*
|
|
27
|
+
* WHAT THE SWAP PRESERVES. The bridge owns the simulation's array, so a swap keeps the arrangement
|
|
28
|
+
* by handing the new simulation the same one. Pins are the STORE's: a byte per row in the position
|
|
29
|
+
* lane, which a freeze remaps with the coordinates. The bridge packs that lane into the
|
|
30
|
+
* simulation's `NodeMask` after every load, because the simulation would otherwise keep spending
|
|
31
|
+
* force on a body the element refuses to move and its own copy of that row would wander away from
|
|
32
|
+
* where the reader put it. A drag holds the same bit temporarily and is not a pin.
|
|
33
|
+
*
|
|
34
|
+
* A FIXED ROW IS THE ONE PLACE THE ELEMENT'S ARRAY IS THE AUTHORITY rather than the simulation's,
|
|
35
|
+
* so it is not published over at all; see {@link SimulationLayoutEngine.publishPositions} for what
|
|
36
|
+
* that costs and why the repair that suggests itself is worse.
|
|
37
|
+
*/
|
|
38
|
+
import { type F32, type GraphSnapshot, type NodeMask } from "@graphty/graph-format";
|
|
39
|
+
import { type CommonLayoutOptions, type ForceAtlas2Options, type FruchtermanReingoldOptions, type LayoutSimulation, type SimulationOptions, type SimulationType, type SpringElectricalOptions } from "@graphty/layout";
|
|
40
|
+
import type { AccelerationController } from "../acceleration/AccelerationController";
|
|
41
|
+
import { type AccelerationPrecision, type GraphAccelerator } from "../acceleration/types";
|
|
42
|
+
import type { Edge } from "../Edge";
|
|
43
|
+
import { GraphtyError } from "../errors";
|
|
44
|
+
import type { DataManager } from "../managers/DataManager";
|
|
45
|
+
import type { Node } from "../Node";
|
|
46
|
+
import { type EdgePosition, LayoutEngine, type Position } from "./LayoutEngine";
|
|
47
|
+
/**
|
|
48
|
+
* How many iterations one `step()` submits.
|
|
49
|
+
*
|
|
50
|
+
* The explicit knob decides whenever a host set one. Otherwise the count is the frame loop's own
|
|
51
|
+
* `stepMultiplier`, raised fourfold once the graph is large enough that reading a million
|
|
52
|
+
* positions back costs more than a frame: above that size the element computes more per batch and
|
|
53
|
+
* accepts a lower position refresh rate, which is the trade design 13 row P12 asks for.
|
|
54
|
+
*
|
|
55
|
+
* It is re-applied at EVERY load, because a freeze can carry a graph across the line in either
|
|
56
|
+
* direction.
|
|
57
|
+
* @param explicit - What a host asked for, or null to let the size decide.
|
|
58
|
+
* @param stepMultiplier - `behavior.layout.stepMultiplier`, the automatic rule's starting point.
|
|
59
|
+
* @param nodeCount - The graph this load is over.
|
|
60
|
+
* @returns The iteration count.
|
|
61
|
+
*/
|
|
62
|
+
export declare function iterationsPerStepFor(explicit: number | null, stepMultiplier: number, nodeCount: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Turns a reader's `nodeMass` record into one value per dense row, and leaves every other form to
|
|
65
|
+
* the simulation.
|
|
66
|
+
*
|
|
67
|
+
* A reader may give `nodeMass` as a number per node ID, as the name of a numeric node column, or
|
|
68
|
+
* not at all. Only the FIRST is resolved here, because it is the only one an accelerator refuses:
|
|
69
|
+
* a GPU never sees a node ID. A node the record says nothing about gets one more than its degree,
|
|
70
|
+
* which is what the simulations themselves apply, so a partial record leaves the rest of the graph
|
|
71
|
+
* exactly as it would have been.
|
|
72
|
+
*
|
|
73
|
+
* Exported beside {@link iterationsPerStepFor} so both rules can be read off without a device, a
|
|
74
|
+
* renderer or a running simulation.
|
|
75
|
+
* @param spec - What the reader set, in any of its three forms.
|
|
76
|
+
* @param undirected - The graph the simulation will be loaded with.
|
|
77
|
+
* @returns The masses, or null when the simulation resolves them itself.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveNodeMass(spec: unknown, undirected: GraphSnapshot): F32 | null;
|
|
80
|
+
/**
|
|
81
|
+
* How a simulation's arrangement maps into the element's scene units.
|
|
82
|
+
*
|
|
83
|
+
* See {@link measureEnvelope}.
|
|
84
|
+
*
|
|
85
|
+
* Exported only because {@link measureEnvelope} returns it and TypeScript's declaration emit
|
|
86
|
+
* needs every named type in a published signature to be exported. Nothing outside this module
|
|
87
|
+
* names the type -- the test destructures the value -- so it is no entry point's surface.
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export interface LayoutEnvelope {
|
|
91
|
+
/** What a simulation-unit offset from {@link LayoutEnvelope.centre} is multiplied by. */
|
|
92
|
+
readonly scale: number;
|
|
93
|
+
/** The arrangement's centre, in the simulation's own units. */
|
|
94
|
+
readonly centre: readonly [number, number, number];
|
|
95
|
+
/**
|
|
96
|
+
* How many rows the measurement actually saw.
|
|
97
|
+
*
|
|
98
|
+
* Zero is the one answer a caller must not act on: it means the arrangement has nothing in
|
|
99
|
+
* it to fit, and the scale and centre beside it are the identity rather than a measurement.
|
|
100
|
+
*/
|
|
101
|
+
readonly placed: number;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Measures the arrangement a simulation currently holds, and says how to publish it.
|
|
105
|
+
*
|
|
106
|
+
* The centre is the mean of the placed rows and the scale is `scalingFactor` divided by the
|
|
107
|
+
* furthest row's distance from that centre, so a published arrangement is exactly
|
|
108
|
+
* `scalingFactor` units from its centre at its widest whatever the simulation's own equilibrium
|
|
109
|
+
* turned out to be. A row that is not finite -- the element's "not laid out yet" -- counts for
|
|
110
|
+
* neither, and an arrangement that measures as a point (see {@link POINT_RADIUS}) publishes at
|
|
111
|
+
* its own size rather than being divided by nothing.
|
|
112
|
+
*
|
|
113
|
+
* A HELD ROW COUNTS FOR NEITHER EITHER, and that is what `held` is for. The publish does not
|
|
114
|
+
* write a row a pin or a drag is holding -- its scene coordinate is the reader's -- so measuring
|
|
115
|
+
* one would fit every OTHER row inside a radius set by a row that is not drawn there: a node
|
|
116
|
+
* dragged past the envelope would shrink the whole graph under the pointer. The caller decides
|
|
117
|
+
* which rows those are, because "held" is the element's business rather than this rule's.
|
|
118
|
+
*
|
|
119
|
+
* Exported beside {@link iterationsPerStepFor} and {@link resolveNodeMass} so the rule can be read
|
|
120
|
+
* off without a device, a renderer or a running simulation.
|
|
121
|
+
* @param positions - A stride-3 array in the simulation's own units, at least `3 * nodeCount` long.
|
|
122
|
+
* @param nodeCount - How many rows of it to measure.
|
|
123
|
+
* @param scalingFactor - The scene-unit radius the arrangement is to be published at.
|
|
124
|
+
* @param held - Answers true for a row the caller will not publish, or null to measure them all.
|
|
125
|
+
* @returns The centre to publish about, the multiplier to publish with, and how many rows were
|
|
126
|
+
* measured.
|
|
127
|
+
*/
|
|
128
|
+
export declare function measureEnvelope(positions: ArrayLike<number>, nodeCount: number, scalingFactor: number, held?: ((row: number) => boolean) | null): LayoutEnvelope;
|
|
129
|
+
/**
|
|
130
|
+
* The resolved options a bridge runs on: the simulation's own knobs, plus the two the frame loop
|
|
131
|
+
* needs.
|
|
132
|
+
*
|
|
133
|
+
* `model` carries whatever the chosen simulation type accepts and WINS over the common members
|
|
134
|
+
* beside it, so one option is never spelled in two places with two answers.
|
|
135
|
+
*/
|
|
136
|
+
export interface SimulationEngineOptions extends CommonLayoutOptions, Omit<SimulationOptions, "iterationsPerStep"> {
|
|
137
|
+
/** The type's own options, already mapped from what the consumer asked for. */
|
|
138
|
+
readonly model: ForceAtlas2Options | FruchtermanReingoldOptions | SpringElectricalOptions;
|
|
139
|
+
/**
|
|
140
|
+
* The radius, in scene units, the published arrangement is fitted to.
|
|
141
|
+
*
|
|
142
|
+
* The element's own envelope, not the simulation's: see the file header. It is every size
|
|
143
|
+
* control the layout publishes rolled into one number -- ForceAtlas2 and Spring publish
|
|
144
|
+
* "Scaling Factor", Spring and spring-electrical publish "Scale" -- because the refit fits
|
|
145
|
+
* the arrangement to exactly this radius, so a multiplier left out of it changes nothing a
|
|
146
|
+
* reader can see. `LayoutManager` is what rolls them up.
|
|
147
|
+
*/
|
|
148
|
+
readonly scalingFactor: number;
|
|
149
|
+
/** Iterations each `step()` submits, or null for the automatic rule re-applied at every load. */
|
|
150
|
+
readonly iterationsPerStep: number | null;
|
|
151
|
+
/** `behavior.layout.stepMultiplier`, which the automatic rule starts from. */
|
|
152
|
+
readonly stepMultiplier: number;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Everything a bridge is built with: ONE constructor argument, because `LayoutEngine.register`
|
|
156
|
+
* accepts only a class whose constructor takes one object and `LayoutEngine.get` calls it with
|
|
157
|
+
* one.
|
|
158
|
+
*/
|
|
159
|
+
export interface SimulationEngineInit {
|
|
160
|
+
/** Which simulation to drive. */
|
|
161
|
+
readonly type: SimulationType;
|
|
162
|
+
/**
|
|
163
|
+
* The registered layout name this bridge is standing in for.
|
|
164
|
+
*
|
|
165
|
+
* Every other engine answers `type` from its class's `static type`, which cannot work here:
|
|
166
|
+
* `LayoutManager` builds THIS class for each of the layouts that declare a
|
|
167
|
+
* `static simulationType`, so the class is the same one for all of them and its own static
|
|
168
|
+
* would name none of them.
|
|
169
|
+
*/
|
|
170
|
+
readonly layoutType: string;
|
|
171
|
+
/** The resolved options. */
|
|
172
|
+
readonly options: SimulationEngineOptions;
|
|
173
|
+
/** The controller that decides where each simulation runs and announces every transition. */
|
|
174
|
+
readonly controller: AccelerationController;
|
|
175
|
+
/** Where a failure goes: the element's error channel, with `source: "layout"`. */
|
|
176
|
+
readonly report: (error: GraphtyError) => void;
|
|
177
|
+
/** The data manager the snapshot, its undirected copy and the position array come from. */
|
|
178
|
+
readonly dataManager: DataManager;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* A `LayoutEngine` that drives one `LayoutSimulation` from `@graphty/layout`.
|
|
182
|
+
*
|
|
183
|
+
* It is registered under no name by itself: `LayoutManager` constructs it for the layout types
|
|
184
|
+
* that declare a `static simulationType`, which is how it receives the controller a registered
|
|
185
|
+
* class could not be handed.
|
|
186
|
+
*/
|
|
187
|
+
export declare class SimulationLayoutEngine extends LayoutEngine {
|
|
188
|
+
#private;
|
|
189
|
+
/** Which simulation this bridge drives. */
|
|
190
|
+
readonly simulationType: SimulationType;
|
|
191
|
+
/** The accelerator member this simulation needs, asked of the controller before every build. */
|
|
192
|
+
readonly capability: string;
|
|
193
|
+
/**
|
|
194
|
+
* Builds a bridge. Nothing is planned and no simulation exists until {@link init} loads one.
|
|
195
|
+
*
|
|
196
|
+
* The parameter is declared as a bare `object` because `LayoutEngine.register` files a class
|
|
197
|
+
* whose constructor takes the options a consumer passed to `setLayout`, and a bridge takes
|
|
198
|
+
* more than that. A caller that means to build one declares its argument as a
|
|
199
|
+
* {@link SimulationEngineInit}, which is what `LayoutManager` does; a caller that arrived
|
|
200
|
+
* through `LayoutEngine.get` is refused on the next line.
|
|
201
|
+
* @param init - A {@link SimulationEngineInit}: the type, the resolved options, the
|
|
202
|
+
* controller, the error channel and the data.
|
|
203
|
+
* @throws A `GraphtyError` with `E_INTERNAL` when no controller was passed.
|
|
204
|
+
*/
|
|
205
|
+
constructor(init: object);
|
|
206
|
+
/**
|
|
207
|
+
* The registered layout name, which every other engine reads off its class's `static type`.
|
|
208
|
+
*
|
|
209
|
+
* Without this the manager's `layoutType`, `getStats().layoutType` and the details of every
|
|
210
|
+
* error this bridge reports would all be undefined, and a 2D/3D switch would ask the element
|
|
211
|
+
* to set a layout called "undefined".
|
|
212
|
+
* @returns The name the consumer set.
|
|
213
|
+
*/
|
|
214
|
+
get type(): string;
|
|
215
|
+
/**
|
|
216
|
+
* The running simulation, or null before the first load and while the bridge is stopped.
|
|
217
|
+
*
|
|
218
|
+
* Exposed so a caller that has to wait for the device -- a screenshot after a pause -- can
|
|
219
|
+
* reach an accelerated simulation's own `flush()`.
|
|
220
|
+
* @returns The simulation.
|
|
221
|
+
*/
|
|
222
|
+
get simulation(): LayoutSimulation | null;
|
|
223
|
+
/**
|
|
224
|
+
* Whether the running simulation is the accelerator's rather than the CPU's.
|
|
225
|
+
* @returns True when the accelerator built it.
|
|
226
|
+
*/
|
|
227
|
+
get isAccelerated(): boolean;
|
|
228
|
+
/**
|
|
229
|
+
* The arithmetic the running simulation computes in, for a caller that labels its results.
|
|
230
|
+
* @returns The precision, which is the CPU's whenever the CPU is running the layout.
|
|
231
|
+
*/
|
|
232
|
+
get precision(): AccelerationPrecision;
|
|
233
|
+
/**
|
|
234
|
+
* How many iterations this bridge has submitted since the simulation was built. Submitted,
|
|
235
|
+
* not retired: an accelerated batch is counted when it goes out, not when it lands.
|
|
236
|
+
* @returns The count.
|
|
237
|
+
*/
|
|
238
|
+
get iterationsDone(): number;
|
|
239
|
+
/**
|
|
240
|
+
* The node masses the running simulation was handed, when the element resolved them itself.
|
|
241
|
+
*
|
|
242
|
+
* A reader may give `nodeMass` as a number per node ID, as the name of a numeric node column,
|
|
243
|
+
* or not at all. Only the FIRST of those three is resolved here, into one value per dense row,
|
|
244
|
+
* because it is the only one an accelerator refuses: a GPU never sees a node ID. The other two
|
|
245
|
+
* are handed to the simulation as they stand and resolved by it at every load, on either path,
|
|
246
|
+
* which is also what keeps them right when a freeze renumbers the graph.
|
|
247
|
+
* @returns The masses, or null when the simulation resolves them itself.
|
|
248
|
+
*/
|
|
249
|
+
get resolvedNodeMass(): F32 | null;
|
|
250
|
+
/**
|
|
251
|
+
* The fixed-node mask the simulation is running with, packed from the store's pin lane.
|
|
252
|
+
* @returns The mask, or an empty one before the first load.
|
|
253
|
+
*/
|
|
254
|
+
get pinnedMask(): NodeMask;
|
|
255
|
+
/**
|
|
256
|
+
* Whether a different accelerator is attached now than when the simulation was built.
|
|
257
|
+
*
|
|
258
|
+
* What `LayoutManager` asks on every controller transition before it swaps: `null` is nothing
|
|
259
|
+
* attached, so a detach, an injection, a device loss and a recovery all answer true, while a
|
|
260
|
+
* transition that leaves the same accelerator attached answers false -- including for a
|
|
261
|
+
* simulation the plan put on the CPU because the graph is below `acceleration.minNodes`.
|
|
262
|
+
* Rebuilding that one on every status change would re-upload the graph and reheat a layout
|
|
263
|
+
* that had settled, and it is a RELOAD that re-plans the threshold, which it does on its own.
|
|
264
|
+
* @param accelerator - What the controller holds now.
|
|
265
|
+
* @returns True when the simulation has to be rebuilt.
|
|
266
|
+
*/
|
|
267
|
+
builtWithChanged(accelerator: GraphAccelerator | null): boolean;
|
|
268
|
+
/**
|
|
269
|
+
* The FIRST load, which is what makes this engine's `init()` different from every other's.
|
|
270
|
+
*
|
|
271
|
+
* `LayoutManager._setLayoutInternal` replays the pinned nodes between `init()` and
|
|
272
|
+
* `setLayoutEngine`, through `setNodePosition` and `pin`, so a load deferred to any later
|
|
273
|
+
* point would meet those calls with no simulation to tell.
|
|
274
|
+
* @returns A promise that resolves once the simulation exists and holds the graph.
|
|
275
|
+
*/
|
|
276
|
+
init(): Promise<void>;
|
|
277
|
+
/**
|
|
278
|
+
* Adopts a snapshot and builds the simulation the controller's plan chose for it.
|
|
279
|
+
* @param snapshot - The graph, as `getSnapshot()` returns it; the bridge derives the
|
|
280
|
+
* undirected copy the simulations require itself.
|
|
281
|
+
* @param positions - The element's stride-3 array, written in place by every batch.
|
|
282
|
+
* @throws A `GraphtyError` with `E_NO_ACCELERATOR` under the `required` policy with nothing
|
|
283
|
+
* attached, or whatever `createSimulation` throws.
|
|
284
|
+
*/
|
|
285
|
+
load(snapshot: GraphSnapshot, positions: F32): void;
|
|
286
|
+
/**
|
|
287
|
+
* Hands the running simulation a new snapshot, rebuilding it first when the plan flipped.
|
|
288
|
+
*
|
|
289
|
+
* The re-plan is the point: a freeze can carry the graph across `acceleration.minNodes` in
|
|
290
|
+
* either direction, and design 9.4 item 4 re-evaluates the threshold at every load.
|
|
291
|
+
* @param snapshot - The snapshot that has just replaced the old one.
|
|
292
|
+
* @param positions - The element's array, re-viewed at the new node count.
|
|
293
|
+
* @throws A `GraphtyError` with `E_NO_ACCELERATOR` under the `required` policy with nothing
|
|
294
|
+
* attached.
|
|
295
|
+
*/
|
|
296
|
+
reload(snapshot: GraphSnapshot, positions: F32): void;
|
|
297
|
+
/**
|
|
298
|
+
* Rebuilds the simulation on whatever the controller holds now, keeping the arrangement.
|
|
299
|
+
*
|
|
300
|
+
* The old simulation is disposed and the new one is loaded with the SAME positions view and
|
|
301
|
+
* the same pins, so an accelerator arriving mid-run continues the layout rather than
|
|
302
|
+
* restarting it, and one leaving hands it to the CPU where the policy allows a CPU.
|
|
303
|
+
* @throws A `GraphtyError` with `E_NO_ACCELERATOR` when the policy is `"required"` and
|
|
304
|
+
* nothing is attached. The bridge is then STOPPED -- no simulation, nothing submitted -- and
|
|
305
|
+
* the next transition that attaches an accelerator brings it back through this same method.
|
|
306
|
+
*/
|
|
307
|
+
replaceSimulation(): void;
|
|
308
|
+
/**
|
|
309
|
+
* Submits one batch, fire and forget.
|
|
310
|
+
*
|
|
311
|
+
* The abstract signature returns nothing, and a GPU simulation's `step()` returns a promise,
|
|
312
|
+
* so the rejection is caught here instead of by a caller. A saturated simulation returns the
|
|
313
|
+
* OLDEST promise already in flight rather than submitting another, which is how it keeps the
|
|
314
|
+
* frame loop from queueing work faster than the device retires it -- so the handlers are
|
|
315
|
+
* attached only when the promise is one this bridge has not seen. They are what closes the
|
|
316
|
+
* controller's work span: a batch landing on a settled simulation is where a GPU layout
|
|
317
|
+
* stops being work on the device.
|
|
318
|
+
*/
|
|
319
|
+
step(): void;
|
|
320
|
+
/**
|
|
321
|
+
* Submits one batch and waits for it, which the pre-step loop and the tests need.
|
|
322
|
+
* @param iterations - Iterations this batch computes.
|
|
323
|
+
* @returns A promise that resolves when the batch has landed, or rejects with its failure.
|
|
324
|
+
*/
|
|
325
|
+
stepAsync(iterations: number): Promise<void>;
|
|
326
|
+
/**
|
|
327
|
+
* Starts the settle count again, on a simulation that has one.
|
|
328
|
+
*
|
|
329
|
+
* `reheat()` is not on the `LayoutSimulation` interface -- both CPU simulations and the GPU
|
|
330
|
+
* ones have it, and a third party's may not -- so it is feature-tested rather than assumed.
|
|
331
|
+
*/
|
|
332
|
+
reheat(): void;
|
|
333
|
+
/**
|
|
334
|
+
* Holds a node still for the duration of a drag, without pinning it.
|
|
335
|
+
*
|
|
336
|
+
* The fixed bit is the same one a pin uses, because it is the only thing that stops a
|
|
337
|
+
* simulation writing the row; what makes this temporary is that {@link endDrag} clears it
|
|
338
|
+
* again unless the drag is about to become a pin.
|
|
339
|
+
* @param n - The node the pointer has taken.
|
|
340
|
+
*/
|
|
341
|
+
beginDrag(n: Node): void;
|
|
342
|
+
/**
|
|
343
|
+
* Gives the node back to the simulation, or leaves it fixed because it is being pinned.
|
|
344
|
+
* A node that was ALREADY PINNED before the pointer took it keeps its bit whatever `pin`
|
|
345
|
+
* says: the store's pin stops the row being published over, but only the fixed bit stops the
|
|
346
|
+
* simulation's own copy of it drifting away from where the reader put it, which the next
|
|
347
|
+
* refit would then have to drag back. Clearing it would leave a node the store still calls
|
|
348
|
+
* pinned being pushed around inside the simulation every frame.
|
|
349
|
+
* @param n - The node the pointer has let go of.
|
|
350
|
+
* @param pin - True when the drag ends in a pin, so the bit stays set.
|
|
351
|
+
*/
|
|
352
|
+
endDrag(n: Node, pin: boolean): void;
|
|
353
|
+
/**
|
|
354
|
+
* Fixes a pinned node in the simulation. The store already holds the pin.
|
|
355
|
+
* @param n - The node that was pinned.
|
|
356
|
+
*/
|
|
357
|
+
pin(n: Node): void;
|
|
358
|
+
/**
|
|
359
|
+
* Releases a node the simulation was holding fixed.
|
|
360
|
+
* @param n - The node that was unpinned.
|
|
361
|
+
*/
|
|
362
|
+
unpin(n: Node): void;
|
|
363
|
+
/**
|
|
364
|
+
* Places one node now. A drag reaches this per pointer move, and `replayPins` once per pin.
|
|
365
|
+
* @param n - The node that moved.
|
|
366
|
+
* @param p - Where it moved to.
|
|
367
|
+
*/
|
|
368
|
+
setNodePosition(n: Node, p: Position): void;
|
|
369
|
+
/**
|
|
370
|
+
* Reads a node's current coordinates, in scene units, out of the element's own position array.
|
|
371
|
+
* @param n - The node to read.
|
|
372
|
+
* @returns Its scene-unit position; the origin for a row nothing has placed.
|
|
373
|
+
*/
|
|
374
|
+
getNodePosition(n: Node): Position;
|
|
375
|
+
/**
|
|
376
|
+
* Reads both endpoints of an edge into the one pair this engine reuses.
|
|
377
|
+
* @param e - The edge to read.
|
|
378
|
+
* @returns The pair, valid until the next call; the origin for an endpoint nothing has placed.
|
|
379
|
+
*/
|
|
380
|
+
getEdgePosition(e: Edge): EdgePosition;
|
|
381
|
+
/**
|
|
382
|
+
* Nothing: the snapshot IS the graph, and the simulation reads it rather than a node list.
|
|
383
|
+
*/
|
|
384
|
+
addNode(): void;
|
|
385
|
+
/**
|
|
386
|
+
* Nothing, for the same reason as {@link addNode}.
|
|
387
|
+
*/
|
|
388
|
+
addEdge(): void;
|
|
389
|
+
/**
|
|
390
|
+
* Every node of the graph, which is the list the FRAME LOOP walks.
|
|
391
|
+
*
|
|
392
|
+
* The bridge keeps no list of its own -- the snapshot is the graph -- but these two getters
|
|
393
|
+
* are not bookkeeping: `UpdateManager` moves a mesh only for a node this one yields, draws an
|
|
394
|
+
* edge only for an edge the next one yields, and frames the camera on their count. An empty
|
|
395
|
+
* iterable would let the simulation rewrite the position array every frame while not one mesh
|
|
396
|
+
* moved. So they answer with the data manager's own collections, which hold exactly what
|
|
397
|
+
* `LayoutManager` hands every other engine through `addNodes` / `addEdges`.
|
|
398
|
+
* @returns The graph's live node collection.
|
|
399
|
+
*/
|
|
400
|
+
get nodes(): Iterable<Node>;
|
|
401
|
+
/**
|
|
402
|
+
* Every edge of the graph; see {@link SimulationLayoutEngine.nodes}.
|
|
403
|
+
* @returns The graph's live edge collection.
|
|
404
|
+
*/
|
|
405
|
+
get edges(): Iterable<Edge>;
|
|
406
|
+
/**
|
|
407
|
+
* Whether the simulation has stopped moving.
|
|
408
|
+
*
|
|
409
|
+
* A bridge with no simulation -- before the first load, or stopped after a swap the policy
|
|
410
|
+
* refused -- reads settled, because nothing is going to move.
|
|
411
|
+
* @returns True when the last completed batch settled.
|
|
412
|
+
*/
|
|
413
|
+
get isSettled(): boolean;
|
|
414
|
+
/**
|
|
415
|
+
* Maps the simulation's arrangement into the element's scene units, and writes it.
|
|
416
|
+
*
|
|
417
|
+
* This is the seam the file header describes. The mapping is remeasured here rather than
|
|
418
|
+
* fixed once, because a ForceAtlas2 graph expands for hundreds of iterations before it
|
|
419
|
+
* settles: a scale taken at the first step would let the arrangement grow out of the frame,
|
|
420
|
+
* and one taken at the last would not exist until the reader had already watched it happen.
|
|
421
|
+
* Remeasured, a settling graph holds its apparent size and only its shape changes.
|
|
422
|
+
*
|
|
423
|
+
* A FIXED ROW IS NEITHER PUBLISHED NOR MEASURED. Its scene-unit coordinate is the reader's --
|
|
424
|
+
* the pointer's, or where a pin left it -- and `LayoutEngine.writeNodePosition` refuses a
|
|
425
|
+
* layout-intent write to a pinned row for every engine in this element, so the skip is that
|
|
426
|
+
* same rule reaching a row a drag is holding as well. It is left out of the measurement for
|
|
427
|
+
* the same reason it is left out of the write: a radius taken over a row that is not drawn
|
|
428
|
+
* there would resize every row that is. The two sides start in step, because
|
|
429
|
+
* every path that fixes a row leaves them in step: a drag writes both through
|
|
430
|
+
* {@link SimulationLayoutEngine.setNodePosition}, and a pin, a freeze and a rebuild all fix a
|
|
431
|
+
* row whose simulation copy this mapping had just published from.
|
|
432
|
+
*
|
|
433
|
+
* THEY DRIFT APART AFTERWARDS, and deliberately. A refit rescales the arrangement around a
|
|
434
|
+
* held row without moving the row, so the longer the arrangement keeps growing the further
|
|
435
|
+
* the simulation's copy of that row sits from where it is drawn. The obvious repair -- write
|
|
436
|
+
* the row back into the simulation whenever the mapping moves -- was tried and is worse than
|
|
437
|
+
* the problem: a simulation treats a written position as a disturbance and reheats, so an
|
|
438
|
+
* accelerated ForceAtlas2 with one pinned node cleared its settle window on every frame and
|
|
439
|
+
* ran the full sixty-second test budget without once reporting itself at rest. Worse, the
|
|
440
|
+
* write changes the arrangement, which changes the refit, which asks for another write. A pin
|
|
441
|
+
* is a scene-unit promise and it is kept; how far the arrangement moves under it is not part
|
|
442
|
+
* of that promise.
|
|
443
|
+
*
|
|
444
|
+
* WHAT A GRAPH OF NOTHING BUT HELD ROWS COSTS. Fitting only the published rows means that the
|
|
445
|
+
* fewer of them there are the less there is to fit, and two free rows a hair apart are spread
|
|
446
|
+
* to the full radius exactly as a two-node graph would be. That is this rule meeting a reader
|
|
447
|
+
* who has pinned almost everything and taken the size out of the layout's hands; it is bounded
|
|
448
|
+
* -- an arrangement that measures as a point publishes at its own size -- and a graph with no
|
|
449
|
+
* free row left keeps the last map rather than falling back to the identity.
|
|
450
|
+
*/
|
|
451
|
+
publishPositions(): void;
|
|
452
|
+
/**
|
|
453
|
+
* Releases the simulation. The accelerator's residency for the snapshot is NOT released here:
|
|
454
|
+
* it is per snapshot and shared with the algorithm runs, and `Graph` frees it at the next
|
|
455
|
+
* freeze and at shutdown.
|
|
456
|
+
*/
|
|
457
|
+
dispose(): void;
|
|
458
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The spring-electrical layout: ngraph's force model, computed on an accelerator.
|
|
3
|
+
*
|
|
4
|
+
* It is registered whatever hardware is present, and `setLayout("spring-electrical")` without an
|
|
5
|
+
* accelerator that implements it fails loudly with `E_NO_ACCELERATOR` rather than quietly
|
|
6
|
+
* arranging the graph some other way. A picker does not have to try it to find out: the layout
|
|
7
|
+
* catalogue's entry for this engine declares `requires: { accelerator: true }`, which a consumer
|
|
8
|
+
* reads beside `capabilities.acceleration.state` and greys the entry out.
|
|
9
|
+
*/
|
|
10
|
+
import type { SimulationType } from "@graphty/layout";
|
|
11
|
+
import { type OptionsSchema } from "../config";
|
|
12
|
+
import { SimulationLayoutEngine } from "./SimulationLayoutEngine";
|
|
13
|
+
/**
|
|
14
|
+
* The spring-electrical 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` beside ngraph, d3, ForceAtlas2, Spring and Kamada-Kawai.
|
|
20
|
+
*/
|
|
21
|
+
export declare class SpringElectricalLayout extends SimulationLayoutEngine {
|
|
22
|
+
static type: string;
|
|
23
|
+
static simulationType: SimulationType;
|
|
24
|
+
static maxDimensions: number;
|
|
25
|
+
static zodOptionsSchema: OptionsSchema;
|
|
26
|
+
/**
|
|
27
|
+
* Get dimension-specific options for the spring-electrical layout.
|
|
28
|
+
* @param dimension - The desired dimension (2 or 3).
|
|
29
|
+
* @returns Options object with dim parameter.
|
|
30
|
+
*/
|
|
31
|
+
static getOptionsForDimension(dimension: 2 | 3): object;
|
|
32
|
+
}
|