@kanzo-tech/graph 0.18.0 → 0.19.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.
@@ -33,6 +33,7 @@ export interface Renderer extends GraphCommands {
33
33
  * `transitionDuration` is 0: the default animates every upload for 800 ms and keeps the loop awake.
34
34
  * The live layout is off unless `simulate` or the toolbar asks, and runs from the current positions.
35
35
  * Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.
36
+ * A failure to draw at all marks the store `failed` through `unrenderable`, never `onFailure` alone.
36
37
  */
37
38
  export declare function createRenderer(host: HTMLDivElement, store: GraphStore, events?: RendererEvents): Renderer | null;
38
39
  //# sourceMappingURL=renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,eAAe,CAAC;AAM7D,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,QAAS,SAAQ,aAAa;IAC7C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,kFAAkF;IAClF,OAAO,IAAI,IAAI,CAAC;IAChB,uFAAuF;IACvF,GAAG,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,GAAG,MAAM,EAAE,CAAC;IACvG,OAAO,IAAI,IAAI,CAAC;CACjB;AAqBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,GAAE,cAAmB,GAAG,QAAQ,GAAG,IAAI,CA8QpH"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,eAAe,CAAC;AAM7D,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,QAAS,SAAQ,aAAa;IAC7C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,kFAAkF;IAClF,OAAO,IAAI,IAAI,CAAC;IAChB,uFAAuF;IACvF,GAAG,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,GAAG,MAAM,EAAE,CAAC;IACvG,OAAO,IAAI,IAAI,CAAC;CACjB;AA0BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,GAAE,cAAmB,GAAG,QAAQ,GAAG,IAAI,CA4RpH"}
@@ -1,41 +1,45 @@
1
- import { Graph as j } from "@cosmos.gl/graph";
2
- import { resolveLook as B } from "./graph-looks.js";
3
- import { forces as x, appearance as H, paint as $ } from "./graph-model.js";
4
- import { resolveSim as M } from "./graph-sim.js";
5
- import { hasWebGL as J, releaseContext as K } from "./webgl.js";
6
- const C = 420, z = 0.18, S = 0.35, V = 20, _ = (s) => [s.x, s.y, s.x + s.w, s.y + s.h];
7
- function Q(s, i) {
8
- if (!i) return s.positions;
9
- const e = s.positions.slice();
10
- for (let l = 0; l < s.size; l++)
11
- i[l] || (e[l * 2] = e[l * 2 + 1] = Number.NaN);
1
+ import { Graph as Q } from "@cosmos.gl/graph";
2
+ import { GraphError as w } from "../core/error.js";
3
+ import { resolveLook as M } from "./graph-looks.js";
4
+ import { forces as C, appearance as V, paint as X } from "./graph-model.js";
5
+ import { resolveSim as q } from "./graph-sim.js";
6
+ import { hasWebGL as $, releaseContext as v } from "./webgl.js";
7
+ const E = 420, I = 0.18, k = 0.35, U = 20, W = 1e4, Z = (a) => [a.x, a.y, a.x + a.w, a.y + a.h];
8
+ function nn(a, i) {
9
+ if (!i) return a.positions;
10
+ const e = a.positions.slice();
11
+ for (let s = 0; s < a.size; s++)
12
+ i[s] || (e[s * 2] = e[s * 2 + 1] = Number.NaN);
12
13
  return e;
13
14
  }
14
- function on(s, i, e = {}) {
15
- const l = (n) => i.getOptions().onFailure(n);
16
- if (!J())
17
- return l("This canvas renders on the GPU, and this browser offers no WebGL context."), null;
18
- let h = M(i.getOptions().sim), f = i.getOptions().simulate ?? !1, k = null, y = null, D = -1;
19
- const F = (n) => {
20
- const t = Math.round(n * V);
21
- t !== D && (D = t, i.reportProgress(t / V));
15
+ function sn(a, i, e = {}) {
16
+ let s = !1;
17
+ const h = (n) => {
18
+ s || i.unrenderable(n);
22
19
  };
23
- let P = B(i.getOptions().look), I = i.getOptions().look;
20
+ if (!$())
21
+ return h(new w("graph/no-webgl", "This browser offers no WebGL context to draw with.")), null;
22
+ let P = q(i.getOptions().sim), f = i.getOptions().simulate ?? !1, b = null, y = null, L = -1;
23
+ const z = (n) => {
24
+ const t = Math.round(n * U);
25
+ t !== L && (L = t, i.reportProgress(t / U));
26
+ };
27
+ let S = M(i.getOptions().look), F = i.getOptions().look;
24
28
  const r = { positions: !0, paint: !0, state: !0, pinned: !0 };
25
- let g = 0, L = !1, T = null, b = null, u = i.getSnapshot(), p = i.getOptions();
26
- const E = () => {
29
+ let g = 0, R = null, D = null, u = i.getSnapshot(), p = i.getOptions();
30
+ const N = () => {
27
31
  var n;
28
32
  return ((n = i.getSnapshot().geometry) == null ? void 0 : n.size) ?? 0;
29
33
  };
30
34
  let o;
31
35
  try {
32
- o = new j(s, {
36
+ o = new Q(a, {
33
37
  // No `spaceSize` here: the box is the corpus's extent, set when the graph has loaded.
34
38
  // `rescalePositions: false` because the corpus's coordinates are the camera's.
35
39
  rescalePositions: !1,
36
40
  transitionDuration: 0,
37
41
  enableSimulation: f,
38
- ...x(h),
42
+ ...C(P),
39
43
  // Frames to convergence: alpha reaches its floor after exactly this many rendered frames.
40
44
  simulationDecay: 400,
41
45
  randomSeed: "kanzo-discovery",
@@ -46,94 +50,100 @@ function on(s, i, e = {}) {
46
50
  onSimulationStart: () => i.report("running"),
47
51
  onSimulationEnd: () => {
48
52
  var n;
49
- i.report("settled"), F(1), (n = e.onFrame) == null || n.call(e);
53
+ i.report("settled"), z(1), (n = e.onFrame) == null || n.call(e);
50
54
  },
51
55
  onSimulationPause: () => i.report("paused"),
52
56
  onSimulationUnpause: () => i.report("running"),
53
- onSimulationTick: (n, t, a) => {
57
+ onSimulationTick: (n, t, l) => {
54
58
  var c, d;
55
- F(o.progress), t !== void 0 && a && ((c = e.onHover) == null || c.call(e, a)), (d = e.onFrame) == null || d.call(e);
59
+ z(o.progress), t !== void 0 && l && ((c = e.onHover) == null || c.call(e, l)), (d = e.onFrame) == null || d.call(e);
56
60
  },
57
61
  onZoom: () => {
58
62
  var n;
59
63
  return (n = e.onFrame) == null ? void 0 : n.call(e);
60
64
  },
61
65
  onPointMouseOver: (n, t) => {
62
- var a;
63
- k = n, (a = e.onHover) == null || a.call(e, t), i.hover(n);
66
+ var l;
67
+ b = n, (l = e.onHover) == null || l.call(e, t), i.hover(n);
64
68
  },
65
69
  onPointMouseOut: () => {
66
70
  var n;
67
- k = null, (n = e.onHover) == null || n.call(e, null), i.hover(null);
71
+ b = null, (n = e.onHover) == null || n.call(e, null), i.hover(null);
68
72
  },
69
73
  onDragStart: () => {
70
- y = k;
74
+ y = b;
71
75
  },
72
76
  onDrag: (n) => {
73
- var t, a;
74
- (t = e.onHover) == null || t.call(e, o.screenToSpacePosition([n.x, n.y])), (a = e.onFrame) == null || a.call(e);
77
+ var t, l;
78
+ (t = e.onHover) == null || t.call(e, o.screenToSpacePosition([n.x, n.y])), (l = e.onFrame) == null || l.call(e);
75
79
  },
76
80
  onDragEnd: () => {
77
81
  const n = y;
78
82
  y = null, n !== null && i.pin([...i.getSnapshot().pinned, n]);
79
83
  },
80
- onPointClick: (n) => R(n),
81
- onBackgroundClick: () => A()
84
+ onPointClick: (n) => A(n),
85
+ onBackgroundClick: () => G()
82
86
  });
83
87
  } catch (n) {
84
- return l(`The renderer failed to start. (${String(n)})`), null;
88
+ return h(new w("graph/no-webgl", "The renderer failed to start.", {}, { cause: n })), null;
85
89
  }
86
- const w = () => {
90
+ const T = () => {
87
91
  g || (g = requestAnimationFrame(() => {
88
- g = 0, q();
92
+ g = 0, j();
89
93
  }));
90
94
  };
91
- function q() {
92
- var N;
93
- const n = i.getSnapshot(), { geometry: t, encoding: a } = n, c = i.getOptions();
95
+ function j() {
96
+ var _;
97
+ const n = i.getSnapshot(), { geometry: t, encoding: l } = n, c = i.getOptions();
94
98
  let d = !1;
95
- if (r.positions && t && (r.positions = !1, U(t), o.setPointPositions(Q(t, n.mask), !0), t.links !== b && (b = t.links, o.setLinks(b), r.paint = r.state = r.pinned = !0), d = !0), r.paint && t && a) {
99
+ if (r.positions && t && (r.positions = !1, Y(t), o.setPointPositions(nn(t, n.mask), !0), t.links !== D && (D = t.links, o.setLinks(D), r.paint = r.state = r.pinned = !0), d = !0), r.paint && t && l) {
96
100
  r.paint = !1;
97
- const m = $(t, a, P, s, c);
98
- o.setPointColors(m.colors), o.setPointSizes(m.sizes), o.setPointShapes(m.shapes), o.setLinkColors(m.linkColors), o.setConfigPartial(H(P, s)), d = !0;
101
+ const m = X(t, l, S, a, c);
102
+ o.setPointColors(m.colors), o.setPointSizes(m.sizes), o.setPointShapes(m.shapes), o.setLinkColors(m.linkColors), o.setConfigPartial(V(S, a)), d = !0;
99
103
  }
100
104
  r.state && t && (r.state = !1, o.setConfigPartial({
101
105
  highlightedPointIndices: n.selection ? n.selection.vertices.filter((m) => m < t.size) : void 0,
102
106
  focusedPointIndex: n.focus === null || n.focus >= t.size ? void 0 : n.focus
103
- })), r.pinned && t && (r.pinned = !1, o.setPinnedPoints(n.pinned.length > 0 ? [...n.pinned] : null)), d && o.render(), t && a && !r.paint && i.reportDrawn(n), (N = e.onFrame) == null || N.call(e);
107
+ })), r.pinned && t && (r.pinned = !1, o.setPinnedPoints(n.pinned.length > 0 ? [...n.pinned] : null)), d && o.render(), t && l && !r.paint && i.reportDrawn(n), (_ = e.onFrame) == null || _.call(e);
104
108
  }
105
- function U(n) {
106
- n === T || !n.extent || (T = n, o.setConfigPartial({ spaceSize: Math.max(n.extent.w, n.extent.h) }), o.fitViewByPointPositions(_(n.extent), 0, z));
109
+ function Y(n) {
110
+ n === R || !n.extent || (R = n, o.setConfigPartial({ spaceSize: Math.max(n.extent.w, n.extent.h) }), o.fitViewByPointPositions(Z(n.extent), 0, I));
107
111
  }
108
- const W = i.subscribe(() => {
109
- const n = i.getSnapshot(), t = i.getOptions();
110
- (n.geometry !== u.geometry || n.mask !== u.mask) && (r.positions = !0), n.encoding !== u.encoding && (r.paint = !0), t.look !== I && (I = t.look, P = B(t.look), r.paint = !0), (t.fill !== p.fill || t.symbol !== p.symbol || t.stroke !== p.stroke) && (r.paint = !0), (n.selection !== u.selection || n.focus !== u.focus) && (r.state = !0), n.pinned !== u.pinned && (r.pinned = !0), t.sim !== p.sim && Z(t.sim), (t.simulate ?? !1) !== (p.simulate ?? !1) && (t.simulate ? O(S) : o.pause()), u = n, p = t, (r.positions || r.paint || r.state || r.pinned) && w();
111
- });
112
- function Z(n) {
113
- const t = M(n), a = Object.keys(t).some((c) => t[c] !== h[c]);
114
- h = t, f && (o.setConfigPartial(x(t)), a && i.getSnapshot().motion !== "paused" && o.start(S));
112
+ function J(n) {
113
+ const t = q(n), l = Object.keys(t).some((c) => t[c] !== P[c]);
114
+ P = t, f && (o.setConfigPartial(C(t)), l && i.getSnapshot().motion !== "paused" && o.start(k));
115
115
  }
116
- function O(n) {
117
- f || (f = !0, o.setConfigPartial({ enableSimulation: !0, ...x(h) })), o.start(n);
116
+ function x(n) {
117
+ f || (f = !0, o.setConfigPartial({ enableSimulation: !0, ...C(P) })), o.start(n);
118
118
  }
119
- function R(n) {
119
+ function A(n) {
120
120
  const t = o.getNeighboringPointIndices(n) ?? [];
121
121
  i.select([n, ...t], "node", "Node"), i.focus(n);
122
122
  }
123
- function A() {
123
+ function G() {
124
124
  i.select(null), i.focus(null);
125
125
  }
126
- o.setConfigPartial(H(P, s)), o.render();
127
- const G = (n) => {
128
- n.preventDefault(), l("The graph's WebGL context was lost. A browser keeps a limited number of them and drops the oldest; reload the page to get one back.");
129
- };
130
- return o.ready.then(() => {
131
- var n;
132
- L || (n = s.querySelector("canvas")) == null || n.addEventListener("webglcontextlost", G);
133
- }), i.report(f && o.isSimulationRunning ? "running" : "settled"), w(), {
126
+ o.setConfigPartial(V(S, a)), o.render();
127
+ const B = (n) => {
128
+ n.preventDefault(), h(new w("graph/context-lost", "The browser took back the WebGL context; reload to get one."));
129
+ }, H = (n, t) => h(new w("graph/no-webgl", "No GPU device came up to draw with.", n, { cause: t })), O = setTimeout(() => H({ after: W }), W);
130
+ o.ready.then(
131
+ () => {
132
+ var n;
133
+ clearTimeout(O), s || (n = a.querySelector("canvas")) == null || n.addEventListener("webglcontextlost", B);
134
+ },
135
+ (n) => {
136
+ clearTimeout(O), H({}, n);
137
+ }
138
+ ), i.report(f && o.isSimulationRunning ? "running" : "settled"), T();
139
+ const K = i.subscribe(() => {
140
+ const n = i.getSnapshot(), t = i.getOptions();
141
+ (n.geometry !== u.geometry || n.mask !== u.mask) && (r.positions = !0), n.encoding !== u.encoding && (r.paint = !0), t.look !== F && (F = t.look, S = M(t.look), r.paint = !0), (t.fill !== p.fill || t.symbol !== p.symbol || t.stroke !== p.stroke) && (r.paint = !0), (n.selection !== u.selection || n.focus !== u.focus) && (r.state = !0), n.pinned !== u.pinned && (r.pinned = !0), t.sim !== p.sim && J(t.sim), (t.simulate ?? !1) !== (p.simulate ?? !1) && (t.simulate ? x(k) : o.pause()), u = n, p = t, (r.positions || r.paint || r.state || r.pinned) && T();
142
+ });
143
+ return {
134
144
  graph: o,
135
145
  repaint() {
136
- r.paint = !0, w();
146
+ r.paint = !0, T();
137
147
  },
138
148
  hit(n) {
139
149
  const t = "rect" in n ? o.findPointsInRect(n.rect) : o.findPointsInPolygon(n.polygon);
@@ -145,35 +155,35 @@ function on(s, i, e = {}) {
145
155
  fit() {
146
156
  var t;
147
157
  const n = (t = i.getSnapshot().geometry) == null ? void 0 : t.extent;
148
- n ? o.fitViewByPointPositions(_(n), C, z) : o.fitView(C, z);
158
+ n ? o.fitViewByPointPositions(Z(n), E, I) : o.fitView(E, I);
149
159
  },
150
160
  pause: () => o.pause(),
151
161
  resume() {
152
- i.getSnapshot().motion === "settled" || !f ? O(S) : o.unpause();
162
+ i.getSnapshot().motion === "settled" || !f ? x(k) : o.unpause();
153
163
  },
154
164
  restart() {
155
- i.pin([]), O(1);
165
+ i.pin([]), x(1);
156
166
  },
157
167
  unpin() {
158
- i.getSnapshot().pinned.length !== 0 && (i.pin([]), i.getSnapshot().motion === "running" && o.start(S));
168
+ i.getSnapshot().pinned.length !== 0 && (i.pin([]), i.getSnapshot().motion === "running" && o.start(k));
159
169
  },
160
170
  reveal(n) {
161
- n >= E() || (R(n), o.zoomToPointByIndex(n, 500, 5, !0));
171
+ n >= N() || (A(n), o.zoomToPointByIndex(n, 500, 5, !0));
162
172
  },
163
173
  frameSelection() {
164
174
  var t;
165
- const n = (((t = i.getSnapshot().selection) == null ? void 0 : t.vertices) ?? []).filter((a) => a < E());
166
- n.length > 0 && o.fitViewByPointIndices(n, C, 0.25);
175
+ const n = (((t = i.getSnapshot().selection) == null ? void 0 : t.vertices) ?? []).filter((l) => l < N());
176
+ n.length > 0 && o.fitViewByPointIndices(n, E, 0.25);
167
177
  },
168
- clear: A,
178
+ clear: G,
169
179
  destroy() {
170
- W(), g && cancelAnimationFrame(g), L = !0;
171
- const n = s.querySelector("canvas");
172
- n == null || n.removeEventListener("webglcontextlost", G), o.destroy(), K(n);
180
+ K(), g && cancelAnimationFrame(g), clearTimeout(O), s = !0;
181
+ const n = a.querySelector("canvas");
182
+ n == null || n.removeEventListener("webglcontextlost", B), o.destroy(), v(n);
173
183
  }
174
184
  };
175
185
  }
176
186
  export {
177
- on as createRenderer
187
+ sn as createRenderer
178
188
  };
179
189
  //# sourceMappingURL=renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","sources":["../../src/render/renderer.ts"],"sourcesContent":["import { Graph } from \"@cosmos.gl/graph\";\nimport type { Geometry } from \"../core/load\";\nimport type { GraphStore } from \"../core/store\";\nimport type { GraphCommands, VertexId } from \"../core/types\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { hasWebGL, releaseContext } from \"./webgl\";\n\nexport interface RendererEvents {\n /** After every frame and every camera move — where the overlays repaint. */\n onFrame?: () => void;\n /** Where the hovered point is in space, as cosmos.gl reports it: no GPU readback per hover. */\n onHover?: (position: [number, number] | null) => void;\n}\n\nexport interface Renderer extends GraphCommands {\n readonly graph: Graph;\n /** The theme moved under the canvas: colours are resolved again, nothing else. */\n repaint(): void;\n /** The drawn points inside a screen rectangle or polygon, once the device is ready. */\n hit(shape: { rect: [[number, number], [number, number]] } | { polygon: [number, number][] }): number[];\n destroy(): void;\n}\n\nconst FIT_DURATION = 420;\nconst FIT_PADDING = 0.18;\nconst REHEAT = 0.35;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n\ntype Extent = NonNullable<Geometry[\"extent\"]>;\nconst corners = (box: Extent) => [box.x, box.y, box.x + box.w, box.y + box.h];\n\n/** The loaded positions, with `NaN` where the page's filter hides a vertex — cosmos.gl draws no such point. */\nfunction shown(geometry: Geometry, mask: Uint8Array | null): Float32Array {\n if (!mask) return geometry.positions;\n const positions = geometry.positions.slice();\n for (let id = 0; id < geometry.size; id++) {\n if (!mask[id]) positions[id * 2] = positions[id * 2 + 1] = Number.NaN;\n }\n return positions;\n}\n\n/**\n * **cosmos.gl's lifetime, and the frame that renders once.** Built once per element; it subscribes to\n * the store and discharges what changed in one `requestAnimationFrame`:\n *\n * - a new graph uploads positions and links, once per corpus; a filter uploads positions alone;\n * - a binding, a look or a theme change uploads colours, sizes and shapes and nothing else;\n * - a selection, a focus or a pin sets config and uploads nothing, and never calls `render()`:\n * `render()` walks every point and link in JS, and `setConfigPartial` asks for its own frame;\n * - the camera reaches nothing: cosmos.gl moves it, and the overlays follow.\n *\n * A vertex's id is its index here, so nothing is resolved between the store and the buffers.\n * `transitionDuration` is 0: the default animates every upload for 800 ms and keeps the loop awake.\n * The live layout is off unless `simulate` or the toolbar asks, and runs from the current positions.\n * Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.\n */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n const fail = (message: string) => store.getOptions().onFailure(message);\n if (!hasWebGL()) {\n fail(\"This canvas renders on the GPU, and this browser offers no WebGL context.\");\n return null;\n }\n\n let sim: Sim = resolveSim(store.getOptions().sim);\n let live = store.getOptions().simulate ?? false;\n let hovering: number | null = null;\n let dragging: number | null = null;\n let reported = -1;\n const progress = (value: number) => {\n const bucket = Math.round(value * PROGRESS_STEPS);\n if (bucket === reported) return;\n reported = bucket;\n store.reportProgress(bucket / PROGRESS_STEPS);\n };\n\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { positions: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let destroyed = false;\n let framed: Geometry | null = null;\n let links: Float32Array | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const size = () => store.getSnapshot().geometry?.size ?? 0;\n\n let graph: Graph;\n try {\n graph = new Graph(host, {\n // No `spaceSize` here: the box is the corpus's extent, set when the graph has loaded.\n // `rescalePositions: false` because the corpus's coordinates are the camera's.\n rescalePositions: false,\n transitionDuration: 0,\n enableSimulation: live,\n ...forces(sim),\n // Frames to convergence: alpha reaches its floor after exactly this many rendered frames.\n simulationDecay: 400,\n randomSeed: \"kanzo-discovery\",\n pixelRatio: window.devicePixelRatio || 1,\n enableDrag: true,\n hoveredPointCursor: \"pointer\",\n attribution: \"\",\n onSimulationStart: () => store.report(\"running\"),\n onSimulationEnd: () => {\n store.report(\"settled\");\n progress(1);\n events.onFrame?.();\n },\n onSimulationPause: () => store.report(\"paused\"),\n onSimulationUnpause: () => store.report(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\n onZoom: () => events.onFrame?.(),\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(index);\n },\n onPointMouseOut: () => {\n hovering = null;\n events.onHover?.(null);\n store.hover(null);\n },\n onDragStart: () => {\n dragging = hovering;\n },\n onDrag: (event) => {\n events.onHover?.(graph.screenToSpacePosition([event.x, event.y]));\n events.onFrame?.();\n },\n onDragEnd: () => {\n const vertex = dragging;\n dragging = null;\n if (vertex !== null) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => focusOn(index),\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(`The renderer failed to start. (${String(error)})`);\n return null;\n }\n\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n draw();\n });\n };\n\n function draw(): void {\n const snapshot = store.getSnapshot();\n const { geometry, encoding } = snapshot;\n const options = store.getOptions();\n let changed = false;\n if (dirty.positions && geometry) {\n dirty.positions = false;\n frameExtent(geometry);\n graph.setPointPositions(shown(geometry, snapshot.mask), true);\n if (geometry.links !== links) {\n links = geometry.links;\n graph.setLinks(links);\n dirty.paint = dirty.state = dirty.pinned = true;\n }\n changed = true;\n }\n if (dirty.paint && geometry && encoding) {\n dirty.paint = false;\n const buffers = paint(geometry, encoding, look, host, options);\n graph.setPointColors(buffers.colors);\n graph.setPointSizes(buffers.sizes);\n graph.setPointShapes(buffers.shapes);\n graph.setLinkColors(buffers.linkColors);\n graph.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && geometry) {\n dirty.state = false;\n graph.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? snapshot.selection.vertices.filter((id) => id < geometry.size) : undefined,\n focusedPointIndex: snapshot.focus === null || snapshot.focus >= geometry.size ? undefined : snapshot.focus,\n });\n }\n if (dirty.pinned && geometry) {\n dirty.pinned = false;\n graph.setPinnedPoints(snapshot.pinned.length > 0 ? [...snapshot.pinned] : null);\n }\n if (changed) graph.render();\n if (geometry && encoding && !dirty.paint) store.reportDrawn(snapshot);\n events.onFrame?.();\n }\n\n function frameExtent(geometry: Geometry): void {\n if (geometry === framed || !geometry.extent) return;\n framed = geometry;\n graph.setConfigPartial({ spaceSize: Math.max(geometry.extent.w, geometry.extent.h) });\n graph.fitViewByPointPositions(corners(geometry.extent), 0, FIT_PADDING);\n }\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n if (snapshot.geometry !== last.geometry || snapshot.mask !== last.mask) dirty.positions = true;\n if (snapshot.encoding !== last.encoding) dirty.paint = true;\n if (options.look !== lookPatch) {\n lookPatch = options.look;\n look = resolveLook(options.look);\n dirty.paint = true;\n }\n if (options.fill !== lastOptions.fill || options.symbol !== lastOptions.symbol || options.stroke !== lastOptions.stroke) {\n dirty.paint = true;\n }\n if (snapshot.selection !== last.selection || snapshot.focus !== last.focus) dirty.state = true;\n if (snapshot.pinned !== last.pinned) dirty.pinned = true;\n if (options.sim !== lastOptions.sim) applyForces(options.sim);\n if ((options.simulate ?? false) !== (lastOptions.simulate ?? false)) {\n if (options.simulate) run(REHEAT);\n else graph.pause();\n }\n last = snapshot;\n lastOptions = options;\n if (dirty.positions || dirty.paint || dirty.state || dirty.pinned) schedule();\n });\n\n function applyForces(patch: Partial<Sim> | undefined): void {\n const next = resolveSim(patch);\n const moved = Object.keys(next).some((key) => next[key as keyof Sim] !== sim[key as keyof Sim]);\n sim = next;\n if (!live) return;\n graph.setConfigPartial(forces(next));\n if (moved && store.getSnapshot().motion !== \"paused\") graph.start(REHEAT);\n }\n\n /** A layout runs from where the points are: enabling cosmos.gl's simulation keeps its positions. */\n function run(alpha: number): void {\n if (!live) {\n live = true;\n graph.setConfigPartial({ enableSimulation: true, ...forces(sim) });\n }\n graph.start(alpha);\n }\n\n function focusOn(vertex: VertexId): void {\n const around = graph.getNeighboringPointIndices(vertex) ?? [];\n store.select([vertex, ...around], \"node\", \"Node\");\n store.focus(vertex);\n }\n\n function clear(): void {\n store.select(null);\n store.focus(null);\n }\n\n // cosmos.gl 3.4 queues every setter and command until its device exists (`ensureDevice`), and its\n // two synchronous hit tests answer `[]` until then; only the canvas element has to wait for `ready`.\n graph.setConfigPartial(appearance(look, host));\n graph.render();\n const onLost = (event: Event) => {\n event.preventDefault();\n fail(\"The graph's WebGL context was lost. A browser keeps a limited number of them and drops the oldest; reload the page to get one back.\");\n };\n void graph.ready.then(() => {\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n });\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n schedule();\n\n return {\n graph,\n repaint() {\n dirty.paint = true;\n schedule();\n },\n hit(shape) {\n const found = \"rect\" in shape ? graph.findPointsInRect(shape.rect) : graph.findPointsInPolygon(shape.polygon);\n return Array.from(found);\n },\n zoomBy(factor) {\n graph.setZoomLevel(graph.getZoomLevel() * factor, 220);\n },\n fit() {\n const extent = store.getSnapshot().geometry?.extent;\n if (extent) graph.fitViewByPointPositions(corners(extent), FIT_DURATION, FIT_PADDING);\n else graph.fitView(FIT_DURATION, FIT_PADDING);\n },\n pause: () => graph.pause(),\n resume() {\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n store.pin([]);\n run(1);\n },\n unpin() {\n if (store.getSnapshot().pinned.length === 0) return;\n store.pin([]);\n if (store.getSnapshot().motion === \"running\") graph.start(REHEAT);\n },\n reveal(vertex) {\n if (vertex >= size()) return;\n focusOn(vertex);\n graph.zoomToPointByIndex(vertex, 500, 5, true);\n },\n frameSelection() {\n const vertices = (store.getSnapshot().selection?.vertices ?? []).filter((id) => id < size());\n if (vertices.length > 0) graph.fitViewByPointIndices(vertices, FIT_DURATION, 0.25);\n },\n clear,\n destroy() {\n unsubscribe();\n if (frame) cancelAnimationFrame(frame);\n destroyed = true;\n // Read here rather than remembered from construction: the element exists only with the device.\n const canvas = host.querySelector(\"canvas\");\n canvas?.removeEventListener(\"webglcontextlost\", onLost);\n graph.destroy();\n releaseContext(canvas);\n },\n };\n}\n"],"names":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","corners","box","shown","geometry","mask","positions","id","createRenderer","host","store","events","fail","message","hasWebGL","sim","resolveSim","live","hovering","dragging","reported","progress","value","bucket","look","resolveLook","lookPatch","dirty","frame","destroyed","framed","links","last","lastOptions","size","_a","graph","Graph","forces","_alpha","index","position","_b","event","vertex","focusOn","clear","error","schedule","draw","snapshot","encoding","options","changed","frameExtent","buffers","paint","appearance","unsubscribe","applyForces","run","patch","next","moved","key","alpha","around","onLost","shape","found","factor","extent","vertices","canvas","releaseContext"],"mappings":"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"}
1
+ {"version":3,"file":"renderer.js","sources":["../../src/render/renderer.ts"],"sourcesContent":["import { Graph } from \"@cosmos.gl/graph\";\nimport { GraphError } from \"../core/error\";\nimport type { Geometry } from \"../core/load\";\nimport type { GraphStore } from \"../core/store\";\nimport type { GraphCommands, VertexId } from \"../core/types\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { hasWebGL, releaseContext } from \"./webgl\";\n\nexport interface RendererEvents {\n /** After every frame and every camera move — where the overlays repaint. */\n onFrame?: () => void;\n /** Where the hovered point is in space, as cosmos.gl reports it: no GPU readback per hover. */\n onHover?: (position: [number, number] | null) => void;\n}\n\nexport interface Renderer extends GraphCommands {\n readonly graph: Graph;\n /** The theme moved under the canvas: colours are resolved again, nothing else. */\n repaint(): void;\n /** The drawn points inside a screen rectangle or polygon, once the device is ready. */\n hit(shape: { rect: [[number, number], [number, number]] } | { polygon: [number, number][] }): number[];\n destroy(): void;\n}\n\nconst FIT_DURATION = 420;\nconst FIT_PADDING = 0.18;\nconst REHEAT = 0.35;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n/**\n * The slowest honest answer for a GPU device: one comes up in milliseconds when it can be made at\n * all, so ten seconds is a device that will not come, not one that is slow.\n */\nconst READY_DEADLINE = 10_000;\n\ntype Extent = NonNullable<Geometry[\"extent\"]>;\nconst corners = (box: Extent) => [box.x, box.y, box.x + box.w, box.y + box.h];\n\n/** The loaded positions, with `NaN` where the page's filter hides a vertex — cosmos.gl draws no such point. */\nfunction shown(geometry: Geometry, mask: Uint8Array | null): Float32Array {\n if (!mask) return geometry.positions;\n const positions = geometry.positions.slice();\n for (let id = 0; id < geometry.size; id++) {\n if (!mask[id]) positions[id * 2] = positions[id * 2 + 1] = Number.NaN;\n }\n return positions;\n}\n\n/**\n * **cosmos.gl's lifetime, and the frame that renders once.** Built once per element; it subscribes to\n * the store and discharges what changed in one `requestAnimationFrame`:\n *\n * - a new graph uploads positions and links, once per corpus; a filter uploads positions alone;\n * - a binding, a look or a theme change uploads colours, sizes and shapes and nothing else;\n * - a selection, a focus or a pin sets config and uploads nothing, and never calls `render()`:\n * `render()` walks every point and link in JS, and `setConfigPartial` asks for its own frame;\n * - the camera reaches nothing: cosmos.gl moves it, and the overlays follow.\n *\n * A vertex's id is its index here, so nothing is resolved between the store and the buffers.\n * `transitionDuration` is 0: the default animates every upload for 800 ms and keeps the loop awake.\n * The live layout is off unless `simulate` or the toolbar asks, and runs from the current positions.\n * Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.\n * A failure to draw at all marks the store `failed` through `unrenderable`, never `onFailure` alone.\n */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n let destroyed = false;\n const fail = (error: unknown) => {\n if (!destroyed) store.unrenderable(error);\n };\n if (!hasWebGL()) {\n fail(new GraphError(\"graph/no-webgl\", \"This browser offers no WebGL context to draw with.\"));\n return null;\n }\n\n let sim: Sim = resolveSim(store.getOptions().sim);\n let live = store.getOptions().simulate ?? false;\n let hovering: number | null = null;\n let dragging: number | null = null;\n let reported = -1;\n const progress = (value: number) => {\n const bucket = Math.round(value * PROGRESS_STEPS);\n if (bucket === reported) return;\n reported = bucket;\n store.reportProgress(bucket / PROGRESS_STEPS);\n };\n\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { positions: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let framed: Geometry | null = null;\n let links: Float32Array | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const size = () => store.getSnapshot().geometry?.size ?? 0;\n\n let graph: Graph;\n try {\n graph = new Graph(host, {\n // No `spaceSize` here: the box is the corpus's extent, set when the graph has loaded.\n // `rescalePositions: false` because the corpus's coordinates are the camera's.\n rescalePositions: false,\n transitionDuration: 0,\n enableSimulation: live,\n ...forces(sim),\n // Frames to convergence: alpha reaches its floor after exactly this many rendered frames.\n simulationDecay: 400,\n randomSeed: \"kanzo-discovery\",\n pixelRatio: window.devicePixelRatio || 1,\n enableDrag: true,\n hoveredPointCursor: \"pointer\",\n attribution: \"\",\n onSimulationStart: () => store.report(\"running\"),\n onSimulationEnd: () => {\n store.report(\"settled\");\n progress(1);\n events.onFrame?.();\n },\n onSimulationPause: () => store.report(\"paused\"),\n onSimulationUnpause: () => store.report(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\n onZoom: () => events.onFrame?.(),\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(index);\n },\n onPointMouseOut: () => {\n hovering = null;\n events.onHover?.(null);\n store.hover(null);\n },\n onDragStart: () => {\n dragging = hovering;\n },\n onDrag: (event) => {\n events.onHover?.(graph.screenToSpacePosition([event.x, event.y]));\n events.onFrame?.();\n },\n onDragEnd: () => {\n const vertex = dragging;\n dragging = null;\n if (vertex !== null) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => focusOn(index),\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(new GraphError(\"graph/no-webgl\", \"The renderer failed to start.\", {}, { cause: error }));\n return null;\n }\n\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n draw();\n });\n };\n\n function draw(): void {\n const snapshot = store.getSnapshot();\n const { geometry, encoding } = snapshot;\n const options = store.getOptions();\n let changed = false;\n if (dirty.positions && geometry) {\n dirty.positions = false;\n frameExtent(geometry);\n graph.setPointPositions(shown(geometry, snapshot.mask), true);\n if (geometry.links !== links) {\n links = geometry.links;\n graph.setLinks(links);\n dirty.paint = dirty.state = dirty.pinned = true;\n }\n changed = true;\n }\n if (dirty.paint && geometry && encoding) {\n dirty.paint = false;\n const buffers = paint(geometry, encoding, look, host, options);\n graph.setPointColors(buffers.colors);\n graph.setPointSizes(buffers.sizes);\n graph.setPointShapes(buffers.shapes);\n graph.setLinkColors(buffers.linkColors);\n graph.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && geometry) {\n dirty.state = false;\n graph.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? snapshot.selection.vertices.filter((id) => id < geometry.size) : undefined,\n focusedPointIndex: snapshot.focus === null || snapshot.focus >= geometry.size ? undefined : snapshot.focus,\n });\n }\n if (dirty.pinned && geometry) {\n dirty.pinned = false;\n graph.setPinnedPoints(snapshot.pinned.length > 0 ? [...snapshot.pinned] : null);\n }\n if (changed) graph.render();\n if (geometry && encoding && !dirty.paint) store.reportDrawn(snapshot);\n events.onFrame?.();\n }\n\n function frameExtent(geometry: Geometry): void {\n if (geometry === framed || !geometry.extent) return;\n framed = geometry;\n graph.setConfigPartial({ spaceSize: Math.max(geometry.extent.w, geometry.extent.h) });\n graph.fitViewByPointPositions(corners(geometry.extent), 0, FIT_PADDING);\n }\n\n function applyForces(patch: Partial<Sim> | undefined): void {\n const next = resolveSim(patch);\n const moved = Object.keys(next).some((key) => next[key as keyof Sim] !== sim[key as keyof Sim]);\n sim = next;\n if (!live) return;\n graph.setConfigPartial(forces(next));\n if (moved && store.getSnapshot().motion !== \"paused\") graph.start(REHEAT);\n }\n\n /** A layout runs from where the points are: enabling cosmos.gl's simulation keeps its positions. */\n function run(alpha: number): void {\n if (!live) {\n live = true;\n graph.setConfigPartial({ enableSimulation: true, ...forces(sim) });\n }\n graph.start(alpha);\n }\n\n function focusOn(vertex: VertexId): void {\n const around = graph.getNeighboringPointIndices(vertex) ?? [];\n store.select([vertex, ...around], \"node\", \"Node\");\n store.focus(vertex);\n }\n\n function clear(): void {\n store.select(null);\n store.focus(null);\n }\n\n // cosmos.gl 3.4 queues every setter and command until its device exists (`ensureDevice`), and its\n // two synchronous hit tests answer `[]` until then; only the canvas element has to wait for `ready`.\n graph.setConfigPartial(appearance(look, host));\n graph.render();\n const onLost = (event: Event) => {\n event.preventDefault();\n fail(new GraphError(\"graph/context-lost\", \"The browser took back the WebGL context; reload to get one.\"));\n };\n const noDevice = (data: GraphError[\"data\"], cause?: unknown) =>\n fail(new GraphError(\"graph/no-webgl\", \"No GPU device came up to draw with.\", data, { cause }));\n // `ready` never settles when cosmos.gl cannot make a device, so the deadline is what ends the wait.\n const deadline = setTimeout(() => noDevice({ after: READY_DEADLINE }), READY_DEADLINE);\n void graph.ready.then(\n () => {\n clearTimeout(deadline);\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n },\n (error: unknown) => {\n clearTimeout(deadline);\n noDevice({}, error);\n },\n );\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n schedule();\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n if (snapshot.geometry !== last.geometry || snapshot.mask !== last.mask) dirty.positions = true;\n if (snapshot.encoding !== last.encoding) dirty.paint = true;\n if (options.look !== lookPatch) {\n lookPatch = options.look;\n look = resolveLook(options.look);\n dirty.paint = true;\n }\n if (options.fill !== lastOptions.fill || options.symbol !== lastOptions.symbol || options.stroke !== lastOptions.stroke) {\n dirty.paint = true;\n }\n if (snapshot.selection !== last.selection || snapshot.focus !== last.focus) dirty.state = true;\n if (snapshot.pinned !== last.pinned) dirty.pinned = true;\n if (options.sim !== lastOptions.sim) applyForces(options.sim);\n if ((options.simulate ?? false) !== (lastOptions.simulate ?? false)) {\n if (options.simulate) run(REHEAT);\n else graph.pause();\n }\n last = snapshot;\n lastOptions = options;\n if (dirty.positions || dirty.paint || dirty.state || dirty.pinned) schedule();\n });\n\n return {\n graph,\n repaint() {\n dirty.paint = true;\n schedule();\n },\n hit(shape) {\n const found = \"rect\" in shape ? graph.findPointsInRect(shape.rect) : graph.findPointsInPolygon(shape.polygon);\n return Array.from(found);\n },\n zoomBy(factor) {\n graph.setZoomLevel(graph.getZoomLevel() * factor, 220);\n },\n fit() {\n const extent = store.getSnapshot().geometry?.extent;\n if (extent) graph.fitViewByPointPositions(corners(extent), FIT_DURATION, FIT_PADDING);\n else graph.fitView(FIT_DURATION, FIT_PADDING);\n },\n pause: () => graph.pause(),\n resume() {\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n store.pin([]);\n run(1);\n },\n unpin() {\n if (store.getSnapshot().pinned.length === 0) return;\n store.pin([]);\n if (store.getSnapshot().motion === \"running\") graph.start(REHEAT);\n },\n reveal(vertex) {\n if (vertex >= size()) return;\n focusOn(vertex);\n graph.zoomToPointByIndex(vertex, 500, 5, true);\n },\n frameSelection() {\n const vertices = (store.getSnapshot().selection?.vertices ?? []).filter((id) => id < size());\n if (vertices.length > 0) graph.fitViewByPointIndices(vertices, FIT_DURATION, 0.25);\n },\n clear,\n destroy() {\n unsubscribe();\n if (frame) cancelAnimationFrame(frame);\n clearTimeout(deadline);\n destroyed = true;\n // Read here rather than remembered from construction: the element exists only with the device.\n const canvas = host.querySelector(\"canvas\");\n canvas?.removeEventListener(\"webglcontextlost\", onLost);\n graph.destroy();\n releaseContext(canvas);\n },\n };\n}\n"],"names":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","READY_DEADLINE","corners","box","shown","geometry","mask","positions","id","createRenderer","host","store","events","destroyed","fail","error","hasWebGL","GraphError","sim","resolveSim","live","hovering","dragging","reported","progress","value","bucket","look","resolveLook","lookPatch","dirty","frame","framed","links","last","lastOptions","size","_a","graph","Graph","forces","_alpha","index","position","_b","event","vertex","focusOn","clear","schedule","draw","snapshot","encoding","options","changed","frameExtent","buffers","paint","appearance","applyForces","patch","next","moved","key","run","alpha","around","onLost","noDevice","data","cause","deadline","unsubscribe","shape","found","factor","extent","vertices","canvas","releaseContext"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanzo-tech/graph",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Kanzo graph view — a whole fossil corpus, read once through its scan and drawn with cosmos.gl, inside the page's Mosaic crossfilter. Sibling of @kanzo-tech/ui, not part of it: the admission rules exclude graphs from the generic vocabulary by name.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,18 +23,18 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "//peers": "All required. cosmos.gl draws; `lucide-react` is the icon set the parts draw their buttons with, `@kanzo-tech/ui`'s own peer; `@fossil-lang/corpus` is the backend — the host opens a corpus with its `open` on `@kanzo-tech/mosaic`'s `engine()` and this package draws it through its `manifest` and `scan`, writing no SQL of its own; `@kanzo-tech/mosaic` carries the crossfilter the graph listens to and publishes into. They were optional while a root barrel with no source and a `./duckdb` entry with one existed side by side; there is one path now and nothing on it is optional (`/docs/design/graph`, *the one host path*). The Mosaic stack itself — mosaic-core, mosaic-sql — is `@kanzo-tech/mosaic`'s peer, declared once there.",
26
- "//fossil": "The code reads `fossil/1` — `manifest`, `scan({ table })`, a global dense `dense_id` — which `0.3.0-alpha.15` is the first to publish, so it is the floor. Only types are imported; `src/layers.test.ts` holds that.",
26
+ "//fossil": "The code reads `fossil/1` — `manifest`, `scan({ table })`, a global dense `dense_id` — which `0.3.0-alpha.15` was the first to publish. The floor is `0.3.0-alpha.19`, the first whose `Engine.query` requires a `signal` and whose `open` and `scan.read` take one and raise coded failures, which `onFailure` hands on whole. Only types are imported; `src/layers.test.ts` holds that.",
27
27
  "peerDependencies": {
28
28
  "@cosmos.gl/graph": "^3.4.0",
29
- "@fossil-lang/corpus": "^0.3.0-alpha.15",
29
+ "@fossil-lang/corpus": "^0.3.0-alpha.19",
30
30
  "lucide-react": ">=1",
31
31
  "react": "^19.0.0",
32
- "@kanzo-tech/ui": "0.18.0",
33
- "@kanzo-tech/mosaic": "0.18.0"
32
+ "@kanzo-tech/ui": "0.19.0",
33
+ "@kanzo-tech/mosaic": "0.19.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@cosmos.gl/graph": "^3.4.0",
37
- "@fossil-lang/corpus": "^0.3.0-alpha.15",
37
+ "@fossil-lang/corpus": "^0.3.0-alpha.19",
38
38
  "@testing-library/dom": "^10.4.1",
39
39
  "@testing-library/react": "^16.3.2",
40
40
  "@types/react": "^19.0.0",
@@ -46,7 +46,7 @@
46
46
  "react": "^19.0.0",
47
47
  "react-dom": "^19.0.0",
48
48
  "rollup-plugin-preserve-directives": "^0.4.0",
49
- "@kanzo-tech/mosaic": "0.18.0"
49
+ "@kanzo-tech/mosaic": "0.19.0"
50
50
  },
51
51
  "//size-limit": "Budgets our code only: `ignore` mirrors the peers the build externalises in vite.config.ts, cosmos.gl included (about 190 kB gzipped on its own, and the consumer pays it once whatever this package does). First measured 2026-09-30 at 19.07 kB, before the lag work of `perf/phase1-lag`; 19.13 kB before the whole-corpus store deleted the tileset, 15.29 kB after it, and the budget follows it down so real growth trips the gate.",
52
52
  "size-limit": [