@graphty/graphty-element 2.2.3 → 2.2.5
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/ai.js +3 -3
- package/dist/catalog.js +5 -5
- package/dist/chunks/{AiManager-DC3JWPeM.js → AiManager-Bd_r1Hei.js} +7 -2
- package/dist/chunks/{DataSource-DEg3igzS.js → DataSource-Dag8H5US.js} +3 -3
- package/dist/chunks/{GraphSession-DDrQWABb.js → GraphSession-mfo75G0q.js} +3308 -3284
- package/dist/chunks/{VoiceInputAdapter-BueUG885.js → VoiceInputAdapter-DszYl6Ha.js} +442 -424
- package/dist/chunks/{XRPivotCameraController-DENGN2uV.js → XRPivotCameraController-BdoMFcON.js} +1 -1
- package/dist/chunks/{capability-check-BC3Qn6fS.js → capability-check-CdoqmrF0.js} +1 -1
- package/dist/chunks/{detect-CqN0mC6u.js → detect-LAOOaxY_.js} +1 -1
- package/dist/chunks/{format-detection-C8vbCSlS.js → format-detection-a0bD5PIB.js} +1 -1
- package/dist/chunks/{index-COss7yTG.js → index-BY1gnMiZ.js} +1001 -848
- package/dist/chunks/{paletteRegistry-NrWOKT-A.js → paletteRegistry-YSpPryiT.js} +13 -13
- package/dist/chunks/{scales-DKsbJE2L.js → scales-DOpwlWuz.js} +3 -3
- package/dist/extend.js +3 -3
- package/dist/graphty-catalog.json +1 -1
- package/dist/graphty.bundle.js +23040 -22842
- package/dist/graphty.js +3 -3
- package/dist/session.js +37 -52
- package/dist/src/Graph.d.ts +3 -0
- package/dist/src/acceleration/AccelerationController.d.ts +11 -0
- package/dist/src/ai/input/VoiceInputAdapter.d.ts +18 -0
- package/dist/src/data/ingest.d.ts +13 -0
- package/dist/src/managers/DataManager.d.ts +51 -0
- package/dist/src/managers/RenderManager.d.ts +21 -0
- package/dist/src/managers/UpdateManager.d.ts +38 -23
- package/dist/src/session/limits.d.ts +24 -5
- package/package.json +5 -5
package/dist/graphty.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as e, a as E, b as r, D as O, E as o, d as S, G as R, e as _, I as t, L, N as C, O as A, R as N, S as n, f as I, g as T, h as g, U as i, i as l } from "./chunks/index-
|
|
2
|
-
import { a as p, S as G, b as f } from "./chunks/paletteRegistry-
|
|
3
|
-
import { D as y, E as D } from "./chunks/DataSource-
|
|
1
|
+
import { A as e, a as E, b as r, D as O, E as o, d as S, G as R, e as _, I as t, L, N as C, O as A, R as N, S as n, f as I, g as T, h as g, U as i, i as l } from "./chunks/index-BY1gnMiZ.js";
|
|
2
|
+
import { a as p, S as G, b as f } from "./chunks/paletteRegistry-YSpPryiT.js";
|
|
3
|
+
import { D as y, E as D } from "./chunks/DataSource-Dag8H5US.js";
|
|
4
4
|
import { k as P, l as U, g as c, h as m, A as u, C as x, i as B } from "./chunks/Algorithm-RQ629NLb.js";
|
|
5
5
|
import { e as H, E as b, N as Y, a as F, P as W, R as k, S as K, d as v, b as w, c as Q } from "./chunks/NodeStyle-DKj7HjMJ.js";
|
|
6
6
|
import { A as j, a as q, G as z, i as J, b as Z } from "./chunks/GraphtyError-BwcnblTH.js";
|
package/dist/session.js
CHANGED
|
@@ -1,26 +1,11 @@
|
|
|
1
|
-
import { R
|
|
2
|
-
import { A as
|
|
3
|
-
import { g as
|
|
4
|
-
import { D as h } from "./chunks/GraphSession-
|
|
5
|
-
import { a as
|
|
6
|
-
import { R as Q,
|
|
7
|
-
import {
|
|
8
|
-
const u =
|
|
9
|
-
/** Above this node count the element draws less visual detail. A shipped default, not measured. */
|
|
10
|
-
largeGraphThreshold: 1e4,
|
|
11
|
-
/** The most nodes this machine is expected to draw at an interactive frame rate. A shipped default, not measured. */
|
|
12
|
-
renderCeiling: 2e5,
|
|
13
|
-
/** The most elements one selection will hold before it refuses to grow. A shipped default, not measured. */
|
|
14
|
-
selectionCap: h,
|
|
15
|
-
/** The most edges drawn at once; beyond it edges are hidden until the view narrows. A shipped default, not measured. */
|
|
16
|
-
edgesDrawn: 5e5,
|
|
17
|
-
/**
|
|
18
|
-
* Above this NODE COUNT an approximable algorithm is approximated rather than computed
|
|
19
|
-
* exactly. A shipped default, not measured. Not to be confused with the cost gate's
|
|
20
|
-
* `exactComputationSeconds`, which is a duration and answers a different question.
|
|
21
|
-
*/
|
|
22
|
-
approximateAboveNodes: 2e3
|
|
23
|
-
}), l = [
|
|
1
|
+
import { R, e as _ } from "./chunks/types-B7bX5c0K.js";
|
|
2
|
+
import { A as c, a as C, G as p, i as m, b as g } from "./chunks/GraphtyError-BwcnblTH.js";
|
|
3
|
+
import { g as O, h as U, i as I } from "./chunks/Algorithm-RQ629NLb.js";
|
|
4
|
+
import { D as h } from "./chunks/GraphSession-mfo75G0q.js";
|
|
5
|
+
import { a as N, b as y, c as D, d as v, Q as w, R as G, e as b, f as x, S as F, T as M, g as z, i as k, h as H, j as Y, k as j } from "./chunks/GraphSession-mfo75G0q.js";
|
|
6
|
+
import { R as Q, t as X, u as B, v as J, w as K, x as V } from "./chunks/paletteRegistry-YSpPryiT.js";
|
|
7
|
+
import { L as s } from "./chunks/scales-DOpwlWuz.js";
|
|
8
|
+
const u = [
|
|
24
9
|
{
|
|
25
10
|
id: "fixed",
|
|
26
11
|
fires: ({ statistics: e, placedNodes: a }) => e.nodeCount > 0 && a >= e.nodeCount,
|
|
@@ -42,60 +27,60 @@ const u = Object.freeze({
|
|
|
42
27
|
reason: "Connected nodes are pulled together and unconnected ones pushed apart, which is the arrangement that shows this graph's structure without being told anything about it."
|
|
43
28
|
}
|
|
44
29
|
];
|
|
45
|
-
function
|
|
30
|
+
function n(e, a) {
|
|
46
31
|
return e.structuralInputs.length > 0 ? !1 : e.sizeRating === "any" || a <= e.sizeRating;
|
|
47
32
|
}
|
|
48
|
-
function
|
|
33
|
+
function T(e, a = {}) {
|
|
49
34
|
const i = {
|
|
50
35
|
statistics: e,
|
|
51
36
|
placedNodes: a.placedNodes ?? 0,
|
|
52
|
-
largeGraphThreshold: a.largeGraphThreshold ??
|
|
37
|
+
largeGraphThreshold: a.largeGraphThreshold ?? h.largeGraphThreshold
|
|
53
38
|
};
|
|
54
|
-
for (const r of
|
|
39
|
+
for (const r of u) {
|
|
55
40
|
if (!r.fires(i))
|
|
56
41
|
continue;
|
|
57
|
-
const o =
|
|
58
|
-
if (o !== void 0 &&
|
|
42
|
+
const o = s.find((d) => d.id === r.id);
|
|
43
|
+
if (o !== void 0 && n(o, e.nodeCount))
|
|
59
44
|
return Object.freeze({ layout: o, reason: r.reason });
|
|
60
45
|
}
|
|
61
|
-
const t =
|
|
46
|
+
const t = s.find((r) => n(r, e.nodeCount));
|
|
62
47
|
return t === void 0 ? void 0 : Object.freeze({
|
|
63
48
|
layout: t,
|
|
64
49
|
reason: "The first arrangement this element can place a graph of this size with."
|
|
65
50
|
});
|
|
66
51
|
}
|
|
67
52
|
export {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
53
|
+
c as ACCELERATION_ERROR_CODES,
|
|
54
|
+
O as ACCELERATION_POLICIES,
|
|
55
|
+
U as ACCELERATION_POLICY_DEFAULT,
|
|
56
|
+
N as DEFAULT_COST_GATE_LIMITS,
|
|
57
|
+
y as DEFAULT_EXACT_COMPUTATION_CAP_SECONDS,
|
|
58
|
+
h as DEFAULT_LIMITS,
|
|
59
|
+
D as DEFAULT_SCOPE_SAMPLE,
|
|
60
|
+
v as DEFAULT_SELECTION_CAP,
|
|
76
61
|
C as GRAPHTY_ERROR_CODES,
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
p as GraphtyError,
|
|
63
|
+
w as QUEUE_POLICIES,
|
|
79
64
|
Q as RESULT_FIELD_NAMES,
|
|
80
65
|
X as RESULT_ROOT,
|
|
81
|
-
|
|
66
|
+
R as RESULT_SHAPES,
|
|
82
67
|
B as RESULT_SHAPE_CONTRACTS,
|
|
83
|
-
|
|
84
|
-
|
|
68
|
+
G as RUN_ID_PATTERN,
|
|
69
|
+
b as RUN_PHASES,
|
|
85
70
|
x as RUN_STATUSES,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
F as SET_OPS,
|
|
72
|
+
M as TERMINAL_RUN_STATUSES,
|
|
73
|
+
z as createGraphSession,
|
|
89
74
|
J as defaultReading,
|
|
90
|
-
|
|
91
|
-
|
|
75
|
+
I as isAccelerationPolicy,
|
|
76
|
+
k as isAlgorithmRunCommand,
|
|
92
77
|
m as isGraphtyError,
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
g as isGraphtyErrorCode,
|
|
79
|
+
_ as isResultShape,
|
|
95
80
|
H as isRunId,
|
|
96
81
|
Y as isRunStatus,
|
|
97
|
-
|
|
82
|
+
j as isTerminalRunStatus,
|
|
98
83
|
K as quotePath,
|
|
99
|
-
|
|
84
|
+
T as recommendLayout,
|
|
100
85
|
V as resultPath
|
|
101
86
|
};
|
package/dist/src/Graph.d.ts
CHANGED
|
@@ -350,6 +350,9 @@ export declare class Graph implements GraphContext {
|
|
|
350
350
|
* present each time a host re-assigned the property -- and a host that re-renders on state
|
|
351
351
|
* change re-assigns it constantly. The old drop guard was silently doing this job; deleting the
|
|
352
352
|
* guard without this would have turned "assign the same edges twice" into "hold them twice".
|
|
353
|
+
*
|
|
354
|
+
* A set past the render ceiling is refused with `E_TOO_LARGE` before an edge is removed, so
|
|
355
|
+
* the graph keeps the edges it had.
|
|
353
356
|
* @param edges - the edges the graph should hold afterwards
|
|
354
357
|
* @param options - The endpoint expressions, the repeat policy, and queue ordering
|
|
355
358
|
* @returns Promise that resolves once the graph holds exactly these edges
|
|
@@ -92,6 +92,17 @@ interface AccelerationControllerOptions {
|
|
|
92
92
|
readonly recoverOnDeviceLoss?: boolean;
|
|
93
93
|
/** How many consecutive recovery attempts to make before giving up. Defaults to 3. */
|
|
94
94
|
readonly maxRecoveryAttempts?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Opens a span around every call-shaped accelerated run, returning what closes it.
|
|
97
|
+
*
|
|
98
|
+
* The element hands in its render manager's `holdFrames`: a GPU readback is delivered as a
|
|
99
|
+
* task and waits behind whatever frame the host is drawing, so a run that is a few
|
|
100
|
+
* milliseconds on the device came back a frame or two later through the element (issue
|
|
101
|
+
* #390). The span covers exactly the accelerated call -- not the decision before it, and not
|
|
102
|
+
* the CPU path -- and is closed however the call ends. A simulation, which steps every frame
|
|
103
|
+
* through {@link AccelerationController.beginWork}, never opens one: it needs the frames.
|
|
104
|
+
*/
|
|
105
|
+
readonly whileRunning?: () => () => void;
|
|
95
106
|
}
|
|
96
107
|
/**
|
|
97
108
|
* Owns hardware acceleration for one session: whether there is any, what it is, and whether a
|
|
@@ -47,6 +47,10 @@ declare global {
|
|
|
47
47
|
}
|
|
48
48
|
/** Callback for voice input start/error events */
|
|
49
49
|
export type VoiceStartCallback = (started: boolean, error?: string) => void;
|
|
50
|
+
/** Why a voice session ended: stopped by the caller, ended by the recogniser, or failed. */
|
|
51
|
+
type VoiceEndReason = "user" | "timeout" | "error";
|
|
52
|
+
/** Callback for a voice session starting (`active` true) or ending (`active` false, with a reason). */
|
|
53
|
+
type VoiceActiveCallback = (active: boolean, reason?: VoiceEndReason) => void;
|
|
50
54
|
/**
|
|
51
55
|
* Voice input adapter using the Web Speech API.
|
|
52
56
|
* Provides voice-to-text functionality with support for interim and final results.
|
|
@@ -57,6 +61,8 @@ export declare class VoiceInputAdapter implements InputAdapter {
|
|
|
57
61
|
private _isActive;
|
|
58
62
|
private callbacks;
|
|
59
63
|
private startCallbacks;
|
|
64
|
+
private activeCallbacks;
|
|
65
|
+
private failed;
|
|
60
66
|
private SpeechRecognitionCtor;
|
|
61
67
|
/**
|
|
62
68
|
* Creates a new VoiceInputAdapter instance.
|
|
@@ -92,10 +98,22 @@ export declare class VoiceInputAdapter implements InputAdapter {
|
|
|
92
98
|
* @param callback - Function called with (started: boolean, error?: string)
|
|
93
99
|
*/
|
|
94
100
|
onStart(callback: VoiceStartCallback): void;
|
|
101
|
+
/**
|
|
102
|
+
* Register a callback for every voice session starting and ending.
|
|
103
|
+
* Unlike {@link VoiceInputAdapter.onStart} it stays registered across sessions.
|
|
104
|
+
* @param callback - Called with (true) on start and (false, reason) on end
|
|
105
|
+
*/
|
|
106
|
+
onActiveChange(callback: VoiceActiveCallback): void;
|
|
95
107
|
/**
|
|
96
108
|
* Clean up resources and remove all callbacks.
|
|
97
109
|
*/
|
|
98
110
|
dispose(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Notify active-change callbacks.
|
|
113
|
+
* @param active - Whether a session is now running
|
|
114
|
+
* @param reason - Why it ended, when it did
|
|
115
|
+
*/
|
|
116
|
+
private notifyActive;
|
|
99
117
|
/**
|
|
100
118
|
* Notify start callbacks and clear them (one-shot).
|
|
101
119
|
* @param started - Whether voice input started successfully
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type { GraphStore } from "./GraphStore";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a value may be used as a graph-format node id.
|
|
4
|
+
*
|
|
5
|
+
* graph-format accepts a string or a FINITE number and throws `E_INVALID_ID` for anything else
|
|
6
|
+
* (`graph-format/src/ids/node-id-map.ts`). The element is looser: a node id is whatever the
|
|
7
|
+
* configured JMESPath expression returns, which is `null` for a record that does not carry the
|
|
8
|
+
* key at all, and the element has always let such a record through and rendered it. So the id is
|
|
9
|
+
* CHECKED here rather than thrown on -- an unusable id leaves the render object exactly as it is
|
|
10
|
+
* today and keeps it out of the store, which is the one place the id has to be real.
|
|
11
|
+
* @param id - the extracted id
|
|
12
|
+
* @returns true when graph-format will accept it
|
|
13
|
+
*/
|
|
14
|
+
export declare function isStorableId(id: unknown): id is string | number;
|
|
2
15
|
/**
|
|
3
16
|
* Push one node record into the element's builder and seed its import position.
|
|
4
17
|
*
|
|
@@ -423,6 +423,36 @@ export declare class DataManager implements Manager {
|
|
|
423
423
|
* @returns the edges, oldest first; empty when there are none
|
|
424
424
|
*/
|
|
425
425
|
getEdgesBetween(srcNodeId: NodeIdType, dstNodeId: NodeIdType): readonly Edge[];
|
|
426
|
+
/**
|
|
427
|
+
* Replace every built edge with a new set, or leave the graph exactly as it was.
|
|
428
|
+
*
|
|
429
|
+
* The ceiling is decided BEFORE anything is removed. Removing first and letting `addEdges`
|
|
430
|
+
* refuse would leave a host that assigned too many edges with its old edges gone and none of
|
|
431
|
+
* the new ones held, which is neither the graph it had nor the one it asked for. The new
|
|
432
|
+
* batch is counted against an emptied graph, since the old edges are what it replaces; a
|
|
433
|
+
* pending edge, whose endpoints have not arrived, survives the replace as it always has.
|
|
434
|
+
* @param edges - the edges the graph should hold afterwards
|
|
435
|
+
* @param options - the endpoint expressions and the repeat policy for this call
|
|
436
|
+
* @throws A `GraphtyError` with `E_TOO_LARGE` when the new set is past the ceiling, and
|
|
437
|
+
* whatever `addEdges` throws.
|
|
438
|
+
*/
|
|
439
|
+
setEdges(edges: Record<string | number, unknown>[], options?: AddEdgesOptions): void;
|
|
440
|
+
/**
|
|
441
|
+
* How many edges a batch would add, by the same tests the ingest loop applies.
|
|
442
|
+
*
|
|
443
|
+
* A record whose endpoint ids graph-format will not store adds nothing (the loop rejects it).
|
|
444
|
+
* Under the `keep` policy every other record is an edge. Under a folding policy a record that
|
|
445
|
+
* repeats an edge the graph holds, or a record earlier in the same batch, folds into it and
|
|
446
|
+
* adds nothing; a repeat is named the way `knownEdgeFor` names it, by record id when one is
|
|
447
|
+
* configured and stored, else by the ordered endpoint pair.
|
|
448
|
+
* @param edges - the batch
|
|
449
|
+
* @param endpoints - the batch's endpoint expressions
|
|
450
|
+
* @param policy - the repeat policy the batch is under
|
|
451
|
+
* @param replacing - true when every held edge is about to be removed, so none of them can be
|
|
452
|
+
* repeated
|
|
453
|
+
* @returns the number of edges the batch would add
|
|
454
|
+
*/
|
|
455
|
+
private edgesAdded;
|
|
426
456
|
/**
|
|
427
457
|
* Removes an edge from the graph
|
|
428
458
|
* @param edgeId - Edge identifier to remove
|
|
@@ -467,6 +497,27 @@ export declare class DataManager implements Manager {
|
|
|
467
497
|
* @returns the node and edge counts the graph holds
|
|
468
498
|
*/
|
|
469
499
|
private heldCounts;
|
|
500
|
+
/**
|
|
501
|
+
* Refuse to grow past what the renderer can draw, instead of freezing the tab.
|
|
502
|
+
*
|
|
503
|
+
* WHY A REFUSAL AND NOT A DEGRADED DRAW. The design says that above the render ceiling the
|
|
504
|
+
* element draws a smaller render set, and above `edgesDrawn` it hides edges until the view
|
|
505
|
+
* narrows. Neither exists yet. What exists is a renderer that, past these counts, exhausts
|
|
506
|
+
* the renderer process and produces no further frame -- measured for issue #405 at 18,000
|
|
507
|
+
* nodes / 180,000 edges on an RTX 4070 SUPER, where the renderer process reached 4.7 GB and
|
|
508
|
+
* died while 17,000 / 170,000 loaded in 17 s. Until the degraded draw lands, the honest
|
|
509
|
+
* behaviour at the ceiling is a coded error the consumer can show, so `DEFAULT_LIMITS` is
|
|
510
|
+
* the number the element enforces rather than a number it merely publishes.
|
|
511
|
+
*
|
|
512
|
+
* `E_TOO_LARGE` is the code because the ceiling is a hard limit of this renderer, and the
|
|
513
|
+
* caller's remedy is the one that code names: load a subset.
|
|
514
|
+
* @param of - what is being counted
|
|
515
|
+
* @param held - how many the graph holds already
|
|
516
|
+
* @param adding - how many this call would add
|
|
517
|
+
* @param limit - the most the renderer can draw
|
|
518
|
+
* @throws A `GraphtyError` with `E_TOO_LARGE` when `held + adding` is past the limit
|
|
519
|
+
*/
|
|
520
|
+
private refuseAboveCeiling;
|
|
470
521
|
/**
|
|
471
522
|
* Clear all data
|
|
472
523
|
*/
|
|
@@ -22,6 +22,8 @@ export declare class RenderManager implements Manager {
|
|
|
22
22
|
graphRoot: TransformNode;
|
|
23
23
|
private renderLoopActive;
|
|
24
24
|
private updateCallback?;
|
|
25
|
+
/** How many callers currently hold the frames back; see {@link holdFrames}. */
|
|
26
|
+
private frameHolds;
|
|
25
27
|
private resizeHandler;
|
|
26
28
|
/**
|
|
27
29
|
* Stands in for Babylon's own pointer handling, which calls preventDefault and then
|
|
@@ -54,6 +56,25 @@ export declare class RenderManager implements Manager {
|
|
|
54
56
|
* Stop the render loop
|
|
55
57
|
*/
|
|
56
58
|
stopRenderLoop(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Keeps the render loop from drawing until the returned function is called.
|
|
61
|
+
*
|
|
62
|
+
* A FRAME IS WHAT A GPU READBACK WAITS BEHIND. Drawing a scene of thousands of meshes keeps
|
|
63
|
+
* the main thread for tens to hundreds of milliseconds, and a promise the GPU resolves --
|
|
64
|
+
* the mapped buffer at the end of a traversal, the frontier count between its levels -- is
|
|
65
|
+
* delivered as a task, which cannot run until the frame that was drawing has finished. A
|
|
66
|
+
* breadth-first search that costs 7 ms on the device came back after 225 ms through the
|
|
67
|
+
* element at 1,000 nodes and after 8.6 s at 10,000, two frames per readback (issue #390).
|
|
68
|
+
* Measured apart, the CPU update of a frame is 2.5 ms and is not what the readback waits on;
|
|
69
|
+
* the draw is 48 ms at 1,000 nodes and is.
|
|
70
|
+
*
|
|
71
|
+
* So a call-shaped accelerated run holds the frames for as long as it is on the device, and
|
|
72
|
+
* the picture stands still for those milliseconds instead of the run stretching to seconds.
|
|
73
|
+
* Holds nest: the frames resume when the last holder releases, and releasing twice is a
|
|
74
|
+
* no-op, so a `finally` cannot over-release.
|
|
75
|
+
* @returns Releases this hold.
|
|
76
|
+
*/
|
|
77
|
+
holdFrames(): () => void;
|
|
57
78
|
/**
|
|
58
79
|
* Update the background color
|
|
59
80
|
* @param color - Hex color string (e.g., "#FFFFFF")
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { Vector3 } from "@babylonjs/core";
|
|
1
2
|
import type { CameraManager } from "../cameras/CameraManager";
|
|
2
3
|
import type { EdgeId, NodeId } from "../catalog/types";
|
|
4
|
+
import { Edge } from "../Edge";
|
|
5
|
+
import type { Node } from "../Node";
|
|
3
6
|
import type { ElementMask } from "../session/scope/index";
|
|
4
7
|
import type { DataManager } from "./DataManager";
|
|
5
8
|
import type { EventManager } from "./EventManager";
|
|
@@ -7,6 +10,34 @@ import type { GraphContext } from "./GraphContext";
|
|
|
7
10
|
import type { Manager } from "./interfaces";
|
|
8
11
|
import type { LayoutManager } from "./LayoutManager";
|
|
9
12
|
import type { StatsManager } from "./StatsManager";
|
|
13
|
+
/** The corners of a box in world space. */
|
|
14
|
+
interface FramingBox {
|
|
15
|
+
min: Vector3;
|
|
16
|
+
max: Vector3;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The box the nodes alone occupy: every visible node, where it is in world space, out to its size.
|
|
20
|
+
* This is what the 2D/3D view-mode switch frames. Zoom-to-fit frames {@link framingBox}, which
|
|
21
|
+
* grows this one by the labels.
|
|
22
|
+
*
|
|
23
|
+
* NO MARGIN on top. A fixed one is paid by every graph, labelled or not, and on a small graph it is
|
|
24
|
+
* most of the picture: one world unit on each side moved a two-node graph's camera from 6.0 to 8.6
|
|
25
|
+
* units out. The cameras pad the fit themselves.
|
|
26
|
+
* @param nodes - The nodes to frame; hidden ones are skipped.
|
|
27
|
+
* @returns The corners, or undefined when no node is visible.
|
|
28
|
+
*/
|
|
29
|
+
export declare function nodeFramingBox(nodes: Iterable<Node>): FramingBox | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The box zoom-to-fit frames: {@link nodeFramingBox} grown by every label on a visible node and
|
|
32
|
+
* every label and arrow caption on a visible edge, so no label is cut off by the edge of the
|
|
33
|
+
* viewport. A label's size depends on its text and font, which is why framing runs on data loads
|
|
34
|
+
* and layout changes and NOT on label edits: see `Graph`, which asks for a framing only from
|
|
35
|
+
* those.
|
|
36
|
+
* @param nodes - The nodes to frame; hidden ones and their labels are skipped.
|
|
37
|
+
* @param edges - The edges whose labels to frame; hidden ones are skipped.
|
|
38
|
+
* @returns The corners, or undefined when no node is visible.
|
|
39
|
+
*/
|
|
40
|
+
export declare function framingBox(nodes: Iterable<Node>, edges: Iterable<Edge>): FramingBox | undefined;
|
|
10
41
|
/**
|
|
11
42
|
* One set of elements the renderer honours, as the session holds it.
|
|
12
43
|
*
|
|
@@ -366,32 +397,17 @@ export declare class UpdateManager implements Manager {
|
|
|
366
397
|
*/
|
|
367
398
|
private largestMove;
|
|
368
399
|
/**
|
|
369
|
-
* Update all nodes
|
|
370
|
-
* @param measure - Whether this frame's bounding box will be used. False skips the
|
|
371
|
-
* measurement entirely, which is most frames.
|
|
372
|
-
* @returns Object containing minimum and maximum bounding box vectors
|
|
400
|
+
* Update all nodes.
|
|
373
401
|
*/
|
|
374
402
|
private updateNodes;
|
|
375
403
|
/**
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* @
|
|
379
|
-
* @param max - Maximum bounds vector
|
|
380
|
-
* @param size - Node size
|
|
381
|
-
* @param axis - Axis to update (x, y, or z)
|
|
382
|
-
*/
|
|
383
|
-
private updateBoundingBoxAxis;
|
|
384
|
-
/**
|
|
385
|
-
* Expand bounding box to include a label mesh
|
|
386
|
-
* @param labelMesh - The label mesh to include
|
|
387
|
-
* @param min - Minimum bounds vector
|
|
388
|
-
* @param max - Maximum bounds vector
|
|
404
|
+
* Measure the graph the camera is about to be framed on. Taken AFTER the nodes and edges have
|
|
405
|
+
* updated, so the labels are where this frame's positions put them.
|
|
406
|
+
* @returns The box, or undefined when nothing is visible.
|
|
389
407
|
*/
|
|
390
|
-
private
|
|
408
|
+
private measure;
|
|
391
409
|
/**
|
|
392
|
-
* Update all edges
|
|
393
|
-
* @param boundingBoxMin - Minimum bounds (optional)
|
|
394
|
-
* @param boundingBoxMax - Maximum bounds (optional)
|
|
410
|
+
* Update all edges.
|
|
395
411
|
*/
|
|
396
412
|
private updateEdges;
|
|
397
413
|
/**
|
|
@@ -405,8 +421,7 @@ export declare class UpdateManager implements Manager {
|
|
|
405
421
|
private willZoomToFit;
|
|
406
422
|
/**
|
|
407
423
|
* Frame the camera on a box {@link UpdateManager.willZoomToFit} has already approved.
|
|
408
|
-
* @param
|
|
409
|
-
* @param boundingBoxMax - Maximum bounds (optional)
|
|
424
|
+
* @param box - The box to frame, or undefined when there is nothing to frame.
|
|
410
425
|
*/
|
|
411
426
|
private applyZoomToFit;
|
|
412
427
|
/**
|
|
@@ -7,11 +7,30 @@
|
|
|
7
7
|
* large-graph threshold of its own, ten times the element's, with nothing between the two to
|
|
8
8
|
* notice they disagreed.
|
|
9
9
|
*
|
|
10
|
-
* So these are published as what they are: SHIPPED DEFAULTS, not measurements
|
|
11
|
-
* is
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* So these are published as what they are: SHIPPED DEFAULTS, not measurements of the machine this
|
|
11
|
+
* code is running on. When `calibrate()` lands it replaces them and `Capabilities.calibration.basis`
|
|
12
|
+
* turns from `"defaults"` into `"probe"`, which is how a consumer can tell which kind of number it
|
|
13
|
+
* is holding.
|
|
14
|
+
*
|
|
15
|
+
* TWO OF THEM ARE ENFORCED, AND WERE MEASURED ONCE. `renderCeiling` and `edgesDrawn` used to be
|
|
16
|
+
* the design table's figures, 200,000 nodes and 500,000 edges, and nothing checked them. The
|
|
17
|
+
* renderer could not reach either: at 18,000 nodes / 180,000 edges the page stopped producing
|
|
18
|
+
* frames (issue #405). The measurement behind the numbers below, taken 2026-09-26 in headless
|
|
19
|
+
* Chromium on an RTX 4070 SUPER with `layout="random"`, ten edges per node and the default
|
|
20
|
+
* style, found that the wall is not the GPU. It is V8's heap: `performance.memory.jsHeapSizeLimit`
|
|
21
|
+
* is 3.5 GB in that Chromium and the renderer draws every edge as two Babylon meshes plus, on
|
|
22
|
+
* the default arrow-headed style, a ShaderMaterial of its own, which costs about 20 KB of heap
|
|
23
|
+
* per edge and 10 KB per node. The heap was at its limit from 15,000 / 150,000 up (every load
|
|
24
|
+
* past that point is garbage-collection bound: 12.6 s, then 19.4 s at 17,000) and the renderer
|
|
25
|
+
* process died at 18,000 / 180,000. Nodes alone are cheap: 200,000 with no edges used 2.0 GB.
|
|
26
|
+
*
|
|
27
|
+
* The ceilings below keep the worst case they allow together, 50,000 nodes AND 100,000 edges,
|
|
28
|
+
* at 2.7 GB of heap (74 % of the limit, loaded in 8.0 s), which leaves room for a layout and a
|
|
29
|
+
* run to allocate. 100,000 nodes with the same edges reached 84 % and 11.4 s, which is why the
|
|
30
|
+
* node ceiling is the lower of the two measured figures. `DataManager` refuses a load past
|
|
31
|
+
* either with `E_TOO_LARGE`; see `refuseAboveCeiling` there for why a refusal and not a
|
|
32
|
+
* degraded draw. When the arrowheads share one material (pull request #394 in flight) the
|
|
33
|
+
* per-edge cost falls and the same measurement should be repeated to raise these.
|
|
15
34
|
*
|
|
16
35
|
* ONE OF THE SIX FIELDS IS ABSENT, and it is worth saying why the other five are not.
|
|
17
36
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphty/graphty-element",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
4
4
|
"description": "A Web Component library for 3D/2D graph visualization built with Lit and Babylon.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"customElements": "./dist/custom-elements.json",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"vitepress": "^1.6.3",
|
|
135
135
|
"vitest": "^3.2.4",
|
|
136
136
|
"@graphty/remote-logger": "^1.3.7",
|
|
137
|
-
"@graphty/webgpu-graph-algorithms": "^0.6.
|
|
137
|
+
"@graphty/webgpu-graph-algorithms": "^0.6.5"
|
|
138
138
|
},
|
|
139
139
|
"peerDependencies": {
|
|
140
140
|
"@ai-sdk/anthropic": "^2.0.50",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"ai": "^5.0.104",
|
|
147
147
|
"encrypt-storage": "^2.14.7",
|
|
148
148
|
"lit": "^3.0.0",
|
|
149
|
-
"@graphty/webgpu-graph-algorithms": "^0.6.
|
|
149
|
+
"@graphty/webgpu-graph-algorithms": "^0.6.5"
|
|
150
150
|
},
|
|
151
151
|
"peerDependenciesMeta": {
|
|
152
152
|
"@ai-sdk/anthropic": {
|
|
@@ -184,9 +184,9 @@
|
|
|
184
184
|
"papaparse": "^5.5.3",
|
|
185
185
|
"toposort": "^2.0.2",
|
|
186
186
|
"zod": "^3.25.28",
|
|
187
|
+
"@graphty/algorithms": "^2.0.3",
|
|
187
188
|
"@graphty/graph-format": "^1.0.5",
|
|
188
|
-
"@graphty/layout": "^1.9.1"
|
|
189
|
-
"@graphty/algorithms": "^2.0.3"
|
|
189
|
+
"@graphty/layout": "^1.9.1"
|
|
190
190
|
},
|
|
191
191
|
"overrides": {
|
|
192
192
|
"storybook": "$storybook"
|