@kanzo-tech/graph 0.13.1 → 0.14.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.
@@ -1,43 +1,43 @@
1
- import { Graph as nt } from "@cosmos.gl/graph";
2
- import { denseOf as it } from "../core/resident.js";
3
- import { tileOfDense as et } from "../core/tile-matrix.js";
4
- import { createComposer as ot } from "./compose.js";
5
- import { resolveLook as U } from "./graph-looks.js";
6
- import { forces as Z, appearance as _, paint as st } from "./graph-model.js";
7
- import { resolveSim as j } from "./graph-sim.js";
8
- import { whenReady as c, isReady as y } from "./when-ready.js";
9
- import { hasWebGL as rt, releaseContext as at } from "./webgl.js";
10
- const b = 420, k = 0.18, L = 0.35, H = 20, C = (u) => [u.x, u.y, u.x + u.w, u.y + u.h];
11
- function xt(u, i, l = {}) {
12
- const M = (t) => i.getOptions().onFailure(t);
13
- if (!rt())
1
+ import { Graph as v } from "@cosmos.gl/graph";
2
+ import { denseOf as ii } from "../core/resident.js";
3
+ import { tileOfDense as ni } from "../core/tile-matrix.js";
4
+ import { createComposer as ti } from "./compose.js";
5
+ import { resolveLook as _ } from "./graph-looks.js";
6
+ import { forces as R, appearance as U, paint as ei } from "./graph-model.js";
7
+ import { resolveSim as Z } from "./graph-sim.js";
8
+ import { hasWebGL as oi, releaseContext as ri } from "./webgl.js";
9
+ const S = 420, y = 0.18, O = 0.35, j = 20, C = (c) => [c.x, c.y, c.x + c.w, c.y + c.h];
10
+ function gi(c, e, o = {}) {
11
+ const M = (i) => e.getOptions().onFailure(i);
12
+ if (!oi())
14
13
  return M("This canvas renders on the GPU, and this browser offers no WebGL context."), null;
15
- let I = j(i.getOptions().sim), R = null, w = null, B = -1;
16
- const D = (t) => {
17
- const n = Math.round(t * H);
18
- n !== B && (B = n, i.reportProgress(n / H));
19
- }, Y = ot();
20
- let m = null, O = U(i.getOptions().look), E = i.getOptions().look;
21
- const a = { compose: !0, paint: !0, state: !0 };
22
- let x = 0, F = null, S = null, d = i.getSnapshot(), P = i.getOptions();
23
- const h = () => (m == null ? void 0 : m.resident) ?? lt, A = () => {
24
- const { height: t, width: n } = u.getBoundingClientRect();
25
- if (!y(e) || n === 0 || t === 0) return null;
26
- const [o, r] = e.screenToSpacePosition([0, 0]), [p, g] = e.screenToSpacePosition([n, t]), f = { xMin: Math.min(o, p), yMin: Math.min(r, g), xMax: Math.max(o, p), yMax: Math.max(r, g) };
27
- return { view: f, perPixel: (f.xMax - f.xMin) / n };
28
- }, z = () => {
29
- const t = A();
30
- t && i.setViewport(t.view);
14
+ let b = Z(e.getOptions().sim), g = e.getOptions().simulate ?? !1, T = null, k = null, F = -1;
15
+ const B = (i) => {
16
+ const n = Math.round(i * j);
17
+ n !== F && (F = n, e.reportProgress(n / j));
18
+ }, Y = ti();
19
+ let d = null, w = _(e.getOptions().look), E = e.getOptions().look;
20
+ const s = { compose: !0, paint: !0, state: !0, pinned: !0 };
21
+ let P = 0, I = !1, A = null, x = null, f = e.getSnapshot(), h = e.getOptions();
22
+ const m = () => (d == null ? void 0 : d.resident) ?? ai, z = () => {
23
+ const { height: i, width: n } = c.getBoundingClientRect();
24
+ if (!t.isReady || n === 0 || i === 0) return null;
25
+ const [a, l] = t.screenToSpacePosition([0, 0]), [u, p] = t.screenToSpacePosition([n, i]), r = { xMin: Math.min(a, u), yMin: Math.min(l, p), xMax: Math.max(a, u), yMax: Math.max(l, p) };
26
+ return { view: r, perPixel: (r.xMax - r.xMin) / n };
27
+ }, G = () => {
28
+ const i = z();
29
+ i && e.setViewport(i.view);
31
30
  };
32
- let e;
31
+ let t;
33
32
  try {
34
- e = new nt(u, {
33
+ t = new v(c, {
35
34
  // No `spaceSize` here: the box is the corpus's extent, set when the matrix arrives.
36
35
  // `rescalePositions: false` because the corpus's coordinates are the camera's — a rescale
37
36
  // between them means the cull and the viewport describe different places.
38
37
  rescalePositions: !1,
39
- enableSimulation: i.getOptions().simulate ?? !1,
40
- ...Z(I),
38
+ transitionDuration: 0,
39
+ enableSimulation: g,
40
+ ...R(b),
41
41
  // Frames to convergence: alpha reaches its floor after exactly this many rendered frames.
42
42
  simulationDecay: 400,
43
43
  randomSeed: "kanzo-discovery",
@@ -45,191 +45,188 @@ function xt(u, i, l = {}) {
45
45
  enableDrag: !0,
46
46
  hoveredPointCursor: "pointer",
47
47
  attribution: "",
48
- onSimulationStart: () => i.report("running"),
48
+ onSimulationStart: () => e.report("running"),
49
49
  onSimulationEnd: () => {
50
- var t;
51
- i.report("settled"), D(1), (t = l.onFrame) == null || t.call(l);
50
+ var i;
51
+ e.report("settled"), B(1), (i = o.onFrame) == null || i.call(o);
52
52
  },
53
- onSimulationPause: () => i.report("paused"),
54
- onSimulationUnpause: () => i.report("running"),
55
- onSimulationTick: () => {
56
- var t;
57
- D(e.progress), (t = l.onFrame) == null || t.call(l);
53
+ onSimulationPause: () => e.report("paused"),
54
+ onSimulationUnpause: () => e.report("running"),
55
+ onSimulationTick: (i, n, a) => {
56
+ var l, u;
57
+ B(t.progress), n !== void 0 && a && ((l = o.onHover) == null || l.call(o, a)), (u = o.onFrame) == null || u.call(o);
58
58
  },
59
59
  onZoom: () => {
60
- var t;
61
- z(), (t = l.onFrame) == null || t.call(l);
60
+ var i;
61
+ G(), (i = o.onFrame) == null || i.call(o);
62
62
  },
63
- onPointMouseOver: (t) => {
64
- R = t, i.hover(h().at(t) ?? null);
63
+ onPointMouseOver: (i, n) => {
64
+ var a;
65
+ T = i, (a = o.onHover) == null || a.call(o, n), e.hover(m().at(i) ?? null);
65
66
  },
66
67
  onPointMouseOut: () => {
67
- R = null, i.hover(null);
68
+ var i;
69
+ T = null, (i = o.onHover) == null || i.call(o, null), e.hover(null);
68
70
  },
69
71
  onDragStart: () => {
70
- w = R;
72
+ k = T;
73
+ },
74
+ onDrag: (i) => {
75
+ var n, a;
76
+ (n = o.onHover) == null || n.call(o, t.screenToSpacePosition([i.x, i.y])), (a = o.onFrame) == null || a.call(o);
71
77
  },
72
78
  onDragEnd: () => {
73
- const t = w === null ? void 0 : h().at(w);
74
- w = null, t !== void 0 && i.pin([...i.getSnapshot().pinned, t]);
79
+ const i = k === null ? void 0 : m().at(k);
80
+ k = null, i !== void 0 && e.pin([...e.getSnapshot().pinned, i]);
75
81
  },
76
- onPointClick: (t) => {
77
- const n = h().at(t);
78
- n !== void 0 && V(n, t);
82
+ onPointClick: (i) => {
83
+ const n = m().at(i);
84
+ n !== void 0 && H(n, i);
79
85
  },
80
86
  onBackgroundClick: () => W()
81
87
  });
82
- } catch (t) {
83
- return M(`The renderer failed to start. (${String(t)})`), null;
88
+ } catch (i) {
89
+ return M(`The renderer failed to start. (${String(i)})`), null;
84
90
  }
85
- const T = () => {
86
- x || (x = requestAnimationFrame(() => {
87
- x = 0, c(e, $);
91
+ const D = () => {
92
+ P || (P = requestAnimationFrame(() => {
93
+ P = 0, $();
88
94
  }));
89
95
  };
90
- function $(t) {
91
- var p, g, f;
92
- const n = i.getSnapshot(), o = i.getOptions();
93
- let r = !1;
94
- if (a.compose && n.matrix) {
95
- a.compose = !1;
96
- const s = Y({
97
- matrix: n.matrix,
98
- typeIndex: n.typeIndex,
99
- binding: n.binding,
100
- modeColumn: n.modeColumn,
101
- domain: n.domain,
102
- visible: n.visible,
103
- cached: n.cached,
104
- perPixel: ((p = A()) == null ? void 0 : p.perPixel) ?? 0
96
+ function $() {
97
+ var l, u, p;
98
+ const i = e.getSnapshot(), n = e.getOptions();
99
+ let a = !1;
100
+ if (s.compose && i.matrix) {
101
+ s.compose = !1;
102
+ const r = Y({
103
+ matrix: i.matrix,
104
+ typeIndex: i.typeIndex,
105
+ binding: i.binding,
106
+ modeColumn: i.modeColumn,
107
+ domain: i.domain,
108
+ visible: i.visible,
109
+ cached: i.cached,
110
+ perPixel: ((l = z()) == null ? void 0 : l.perPixel) ?? 0
105
111
  });
106
- if (s && (m = s, t.setPointPositions(s.positions, !0), t.setLinks(s.links), a.paint = !0, a.state = !0, r = !0, (g = l.onComposed) == null || g.call(l, s), S !== null && s.resident.indexOf(S) !== void 0)) {
107
- const tt = S;
108
- S = null, queueMicrotask(() => q(tt));
112
+ if (r && (d = r, t.setPointPositions(r.positions, !0), t.setLinks(r.links), s.paint = !0, s.state = !0, s.pinned = !0, a = !0, (u = o.onComposed) == null || u.call(o, r), x !== null && r.resident.indexOf(x) !== void 0)) {
113
+ const X = x;
114
+ x = null, queueMicrotask(() => q(X));
109
115
  }
110
- const v = s && { marks: s.marks, represented: s.represented, domain: s.domain, tally: s.tally };
111
- i.reportDrawn(n.visible, v);
116
+ const Q = r && { marks: r.marks, represented: r.represented, domain: r.domain, tally: r.tally };
117
+ e.reportDrawn(i.visible, Q);
112
118
  }
113
- if (a.paint && m) {
114
- a.paint = !1;
115
- const s = st(m, O, u, o);
116
- t.setPointColors(s.colors), t.setPointSizes(s.sizes), t.setPointShapes(s.shapes), t.setLinkColors(s.linkColors), t.setLinkWidths(s.linkWidths), t.setConfigPartial(_(O, u)), r = !0;
119
+ if (s.paint && d) {
120
+ s.paint = !1;
121
+ const r = ei(d, w, c, n);
122
+ t.setPointColors(r.colors), t.setPointSizes(r.sizes), t.setPointShapes(r.shapes), t.setLinkColors(r.linkColors), t.setLinkWidths(r.linkWidths), t.setConfigPartial(U(w, c)), a = !0;
117
123
  }
118
- if (a.state && m) {
119
- a.state = !1;
120
- const s = m.resident;
124
+ if (s.state && d) {
125
+ s.state = !1;
126
+ const r = d.resident;
121
127
  t.setConfigPartial({
122
- highlightedPointIndices: n.selection ? s.indicesOf(n.selection.vertices) : void 0,
123
- focusedPointIndex: n.focus === null ? void 0 : s.indexOf(n.focus)
128
+ highlightedPointIndices: i.selection ? r.indicesOf(i.selection.vertices) : void 0,
129
+ focusedPointIndex: i.focus === null ? void 0 : r.indexOf(i.focus)
124
130
  });
125
- const v = s.indicesOf(n.pinned);
126
- t.setPinnedPoints(v.length > 0 ? v : null), r = !0;
127
131
  }
128
- r && t.render(), (f = l.onFrame) == null || f.call(l);
132
+ if (s.pinned && d) {
133
+ s.pinned = !1;
134
+ const r = d.resident.indicesOf(i.pinned);
135
+ t.setPinnedPoints(r.length > 0 ? r : null);
136
+ }
137
+ a && t.render(), (p = o.onFrame) == null || p.call(o);
129
138
  }
130
- const G = (t) => {
131
- var o;
132
- const n = (o = t.matrix) == null ? void 0 : o.extent;
133
- !n || t.matrix === F || (F = t.matrix, c(e, (r) => {
134
- r.setConfigPartial({ spaceSize: Math.max(n.w, n.h) }), r.fitViewByPointPositions(C(n), 0, k), z();
139
+ const V = (i) => {
140
+ var a;
141
+ const n = (a = i.matrix) == null ? void 0 : a.extent;
142
+ !n || i.matrix === A || (A = i.matrix, t.setConfigPartial({ spaceSize: Math.max(n.w, n.h) }), t.fitViewByPointPositions(C(n), 0, y), t.ready.then(() => {
143
+ I || G();
135
144
  }));
136
- }, J = i.subscribe(() => {
137
- const t = i.getSnapshot(), n = i.getOptions();
138
- G(t), (t.visible !== d.visible || t.binding !== d.binding || t.domain !== d.domain) && (a.compose = !0), n.look !== E && (E = n.look, O = U(n.look), a.paint = !0), (n.fill !== P.fill || n.symbol !== P.symbol || n.stroke !== P.stroke) && (a.paint = !0), (t.selection !== d.selection || t.focus !== d.focus || t.pinned !== d.pinned) && (a.state = !0), (n.sim !== P.sim || n.simulate !== P.simulate) && K(n.sim, n.simulate), d = t, P = n, (a.compose || a.paint || a.state) && T();
145
+ }, J = e.subscribe(() => {
146
+ const i = e.getSnapshot(), n = e.getOptions();
147
+ V(i), (i.visible !== f.visible || i.binding !== f.binding || i.domain !== f.domain) && (s.compose = !0), n.look !== E && (E = n.look, w = _(n.look), s.paint = !0), (n.fill !== h.fill || n.symbol !== h.symbol || n.stroke !== h.stroke) && (s.paint = !0), (i.selection !== f.selection || i.focus !== f.focus) && (s.state = !0), i.pinned !== f.pinned && (s.pinned = !0), n.sim !== h.sim && K(n.sim), (n.simulate ?? !1) !== (h.simulate ?? !1) && (n.simulate ? L(O) : t.pause()), f = i, h = n, (s.compose || s.paint || s.state || s.pinned) && D();
139
148
  });
140
- function K(t, n = !1) {
141
- const o = j(t), r = Object.keys(o).some((p) => o[p] !== I[p]);
142
- I = o, c(e, (p) => {
143
- p.setConfigPartial({ enableSimulation: n, ...Z(o) }), n && r && p.start(L);
144
- });
149
+ function K(i) {
150
+ const n = Z(i), a = Object.keys(n).some((l) => n[l] !== b[l]);
151
+ b = n, g && (t.setConfigPartial(R(n)), a && e.getSnapshot().motion !== "paused" && t.start(O));
152
+ }
153
+ function L(i) {
154
+ g || (g = !0, t.setConfigPartial({ enableSimulation: !0, ...R(b) })), t.start(i);
145
155
  }
146
- function V(t, n) {
147
- const o = h(), r = y(e) ? o.verticesAt(e.getNeighboringPointIndices(n)) : [];
148
- i.select([t, ...r], "node", "Node"), i.focus(t);
156
+ function H(i, n) {
157
+ const l = m().verticesAt(t.getNeighboringPointIndices(n));
158
+ e.select([i, ...l], "node", "Node"), e.focus(i);
149
159
  }
150
160
  function W() {
151
- i.select(null), i.focus(null);
161
+ e.select(null), e.focus(null);
152
162
  }
153
- function q(t) {
154
- var g, f;
155
- const n = h().indexOf(t);
163
+ function q(i) {
164
+ var p, r;
165
+ const n = m().indexOf(i);
156
166
  if (n !== void 0) {
157
- V(t, n), c(e, (s) => s.zoomToPointByIndex(n, 500, 5, !0));
167
+ H(i, n), t.zoomToPointByIndex(n, 500, 5, !0);
158
168
  return;
159
169
  }
160
- const o = i.getSnapshot().matrix, r = o ? et(o, it(t)) : null, p = r && ((f = (g = o == null ? void 0 : o.tileMatrices[r.z]) == null ? void 0 : g.tiles[r.tile]) == null ? void 0 : f.bbox);
161
- p && (S = t, c(e, (s) => s.fitViewByPointPositions(C(p), b, k)));
170
+ const a = e.getSnapshot().matrix, l = a ? ni(a, ii(i)) : null, u = l && ((r = (p = a == null ? void 0 : a.tileMatrices[l.z]) == null ? void 0 : p.tiles[l.tile]) == null ? void 0 : r.bbox);
171
+ u && (x = i, t.fitViewByPointPositions(C(u), S, y));
162
172
  }
163
- y(e);
164
- const Q = c(e, (t) => {
165
- t.setConfigPartial(_(O, u)), t.render();
166
- }), N = (t) => {
167
- t.preventDefault(), M("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.");
168
- }, X = c(e, () => {
169
- var t;
170
- (t = u.querySelector("canvas")) == null || t.addEventListener("webglcontextlost", N);
171
- });
172
- return i.report(i.getOptions().simulate && e.isSimulationRunning ? "running" : "settled"), G(d), T(), {
173
- graph: e,
174
- resident: h,
175
- composition: () => m,
173
+ t.setConfigPartial(U(w, c)), t.render();
174
+ const N = (i) => {
175
+ i.preventDefault(), M("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.");
176
+ };
177
+ return t.ready.then(() => {
178
+ var i;
179
+ I || (i = c.querySelector("canvas")) == null || i.addEventListener("webglcontextlost", N);
180
+ }), e.report(g && t.isSimulationRunning ? "running" : "settled"), V(f), D(), {
181
+ graph: t,
182
+ resident: m,
183
+ composition: () => d,
176
184
  repaint() {
177
- a.paint = !0, T();
185
+ s.paint = !0, D();
178
186
  },
179
- hit(t) {
180
- if (!y(e)) return [];
181
- const n = "rect" in t ? e.findPointsInRect(t.rect) : e.findPointsInPolygon(t.polygon);
187
+ hit(i) {
188
+ const n = "rect" in i ? t.findPointsInRect(i.rect) : t.findPointsInPolygon(i.polygon);
182
189
  return Array.from(n);
183
190
  },
184
- zoomBy(t) {
185
- c(e, (n) => n.setZoomLevel(n.getZoomLevel() * t, 220));
191
+ zoomBy(i) {
192
+ t.setZoomLevel(t.getZoomLevel() * i, 220);
186
193
  },
187
194
  fit() {
188
195
  var n;
189
- const t = (n = i.getSnapshot().matrix) == null ? void 0 : n.extent;
190
- c(
191
- e,
192
- (o) => t ? o.fitViewByPointPositions(C(t), b, k) : o.fitView(b, k)
193
- );
196
+ const i = (n = e.getSnapshot().matrix) == null ? void 0 : n.extent;
197
+ i ? t.fitViewByPointPositions(C(i), S, y) : t.fitView(S, y);
194
198
  },
195
- pause: () => c(e, (t) => t.pause()),
199
+ pause: () => t.pause(),
196
200
  resume() {
197
- const t = i.getSnapshot().motion === "settled";
198
- c(e, (n) => t ? n.start(L) : n.unpause());
201
+ e.getSnapshot().motion === "settled" || !g ? L(O) : t.unpause();
199
202
  },
200
203
  restart() {
201
- i.pin([]), c(e, (t) => t.start(1));
204
+ e.pin([]), L(1);
202
205
  },
203
206
  unpin() {
204
- i.getSnapshot().pinned.length !== 0 && (i.pin([]), c(e, (t) => t.start(L)));
207
+ e.getSnapshot().pinned.length !== 0 && (e.pin([]), e.getSnapshot().motion === "running" && t.start(O));
205
208
  },
206
209
  reveal: q,
207
- frameBox(t, { duration: n = b, padding: o = k } = {}) {
208
- c(e, (r) => r.fitViewByPointPositions(C(t), n, o));
210
+ frameBox(i, { duration: n = S, padding: a = y } = {}) {
211
+ t.fitViewByPointPositions(C(i), n, a);
209
212
  },
210
213
  frameSelection() {
211
214
  var n;
212
- const t = h().indicesOf(((n = i.getSnapshot().selection) == null ? void 0 : n.vertices) ?? []);
213
- t.length > 0 && c(e, (o) => o.fitViewByPointIndices(t, b, 0.25));
215
+ const i = m().indicesOf(((n = e.getSnapshot().selection) == null ? void 0 : n.vertices) ?? []);
216
+ i.length > 0 && t.fitViewByPointIndices(i, S, 0.25);
214
217
  },
215
218
  clear: W,
216
219
  destroy() {
217
- J(), x && cancelAnimationFrame(x), Q(), X();
218
- const t = u.querySelector("canvas");
219
- t == null || t.removeEventListener("webglcontextlost", N), e.destroy(), at(t);
220
+ J(), P && cancelAnimationFrame(P), I = !0;
221
+ const i = c.querySelector("canvas");
222
+ i == null || i.removeEventListener("webglcontextlost", N), t.destroy(), ri(i);
220
223
  }
221
224
  };
222
225
  }
223
- const lt = {
224
- size: 0,
225
- indexOf: () => {
226
- },
227
- at: () => {
228
- },
229
- indicesOf: () => [],
230
- verticesAt: () => []
231
- };
226
+ const ai = { size: 0, indexOf: () => {
227
+ }, at: () => {
228
+ }, indicesOf: () => [], verticesAt: () => [] };
232
229
  export {
233
- xt as createRenderer
230
+ gi as createRenderer
234
231
  };
235
232
  //# 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 { Box } from \"@fossil-lang/corpus\";\nimport type { Resident, VertexId } from \"../core/resident\";\nimport { denseOf } from \"../core/resident\";\nimport type { GraphSnapshot, GraphStore } from \"../core/store\";\nimport { tileOfDense, type Viewport } from \"../core/tile-matrix\";\nimport type { GraphCommands } from \"../core/types\";\nimport { createComposer, type Composition } from \"./compose\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { isReady, whenReady } from \"./when-ready\";\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 /** A new composition was uploaded. */\n onComposed?: (composition: Composition) => void;\n}\n\nexport interface Renderer extends GraphCommands {\n readonly graph: Graph;\n resident(): Resident;\n composition(): Composition | null;\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\nconst corners = (box: Box) => [box.x, box.y, box.x + box.w, box.y + box.h];\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 change of visible tiles recomposes, and dirties positions, links and the per-point arrays;\n * - a look or a theme change dirties colours, sizes and shapes and nothing else;\n * - a selection, a focus or a pin sets two config fields and uploads nothing;\n * - a snapshot that changed none of those schedules nothing.\n *\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 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 const compose = createComposer();\n let composition: Composition | null = null;\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { compose: true, paint: true, state: true };\n let frame = 0;\n let framed: GraphSnapshot[\"matrix\"] = null;\n let pendingReveal: VertexId | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const resident = () => composition?.resident ?? EMPTY;\n\n const viewport = (): { view: Viewport; perPixel: number } | null => {\n const { height, width } = host.getBoundingClientRect();\n if (!isReady(graph) || width === 0 || height === 0) return null;\n const [ax, ay] = graph.screenToSpacePosition([0, 0]);\n const [bx, by] = graph.screenToSpacePosition([width, height]);\n const view = { xMin: Math.min(ax, bx), yMin: Math.min(ay, by), xMax: Math.max(ax, bx), yMax: Math.max(ay, by) };\n return { view, perPixel: (view.xMax - view.xMin) / width };\n };\n const observe = () => {\n const camera = viewport();\n if (camera) store.setViewport(camera.view);\n };\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 matrix arrives.\n // `rescalePositions: false` because the corpus's coordinates are the camera's — a rescale\n // between them means the cull and the viewport describe different places.\n rescalePositions: false,\n enableSimulation: store.getOptions().simulate ?? false,\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: () => {\n progress(graph.progress);\n events.onFrame?.();\n },\n onZoom: () => {\n observe();\n events.onFrame?.();\n },\n onPointMouseOver: (index) => {\n hovering = index;\n store.hover(resident().at(index) ?? null);\n },\n onPointMouseOut: () => {\n hovering = null;\n store.hover(null);\n },\n onDragStart: () => {\n dragging = hovering;\n },\n onDragEnd: () => {\n const vertex = dragging === null ? undefined : resident().at(dragging);\n dragging = null;\n if (vertex !== undefined) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => {\n const vertex = resident().at(index);\n if (vertex !== undefined) focusOn(vertex, index);\n },\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 whenReady(graph, draw);\n });\n };\n\n function draw(ready: Graph): void {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n let changed = false;\n if (dirty.compose && snapshot.matrix) {\n dirty.compose = false;\n const next = compose({\n matrix: snapshot.matrix,\n typeIndex: snapshot.typeIndex,\n binding: snapshot.binding,\n modeColumn: snapshot.modeColumn,\n domain: snapshot.domain,\n visible: snapshot.visible,\n cached: snapshot.cached,\n perPixel: viewport()?.perPixel ?? 0,\n });\n if (next) {\n composition = next;\n ready.setPointPositions(next.positions, true);\n ready.setLinks(next.links);\n dirty.paint = true;\n dirty.state = true;\n changed = true;\n events.onComposed?.(next);\n if (pendingReveal !== null && next.resident.indexOf(pendingReveal) !== undefined) {\n const vertex = pendingReveal;\n pendingReveal = null;\n queueMicrotask(() => reveal(vertex));\n }\n }\n const drawn = next && { marks: next.marks, represented: next.represented, domain: next.domain, tally: next.tally };\n store.reportDrawn(snapshot.visible, drawn);\n }\n if (dirty.paint && composition) {\n dirty.paint = false;\n const buffers = paint(composition, look, host, options);\n ready.setPointColors(buffers.colors);\n ready.setPointSizes(buffers.sizes);\n ready.setPointShapes(buffers.shapes);\n ready.setLinkColors(buffers.linkColors);\n ready.setLinkWidths(buffers.linkWidths);\n ready.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && composition) {\n dirty.state = false;\n const drawn = composition.resident;\n ready.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? drawn.indicesOf(snapshot.selection.vertices) : undefined,\n focusedPointIndex: snapshot.focus === null ? undefined : drawn.indexOf(snapshot.focus),\n });\n const pinned = drawn.indicesOf(snapshot.pinned);\n ready.setPinnedPoints(pinned.length > 0 ? pinned : null);\n changed = true;\n }\n if (changed) ready.render();\n events.onFrame?.();\n }\n\n const frameExtent = (snapshot: GraphSnapshot) => {\n const extent = snapshot.matrix?.extent;\n if (!extent || snapshot.matrix === framed) return;\n framed = snapshot.matrix;\n whenReady(graph, (ready) => {\n ready.setConfigPartial({ spaceSize: Math.max(extent.w, extent.h) });\n ready.fitViewByPointPositions(corners(extent), 0, FIT_PADDING);\n observe();\n });\n };\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n frameExtent(snapshot);\n if (snapshot.visible !== last.visible || snapshot.binding !== last.binding || snapshot.domain !== last.domain) {\n dirty.compose = true;\n }\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 || snapshot.pinned !== last.pinned) {\n dirty.state = true;\n }\n if (options.sim !== lastOptions.sim || options.simulate !== lastOptions.simulate) applyForces(options.sim, options.simulate);\n last = snapshot;\n lastOptions = options;\n if (dirty.compose || dirty.paint || dirty.state) schedule();\n });\n\n function applyForces(patch: Partial<Sim> | undefined, simulate = false): 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 whenReady(graph, (ready) => {\n ready.setConfigPartial({ enableSimulation: simulate, ...forces(next) });\n if (simulate && moved) ready.start(REHEAT);\n });\n }\n\n function focusOn(vertex: VertexId, index: number): void {\n const drawn = resident();\n const around = isReady(graph) ? drawn.verticesAt(graph.getNeighboringPointIndices(index)) : [];\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 /** Centre and select one vertex; one that is not drawn is framed by its tile first, then revealed. */\n function reveal(vertex: VertexId): void {\n const index = resident().indexOf(vertex);\n if (index !== undefined) {\n focusOn(vertex, index);\n whenReady(graph, (ready) => ready.zoomToPointByIndex(index, 500, 5, true));\n return;\n }\n const matrix = store.getSnapshot().matrix;\n const address = matrix ? tileOfDense(matrix, denseOf(vertex)) : null;\n const box = address && matrix?.tileMatrices[address.z]?.tiles[address.tile]?.bbox;\n if (!box) return;\n pendingReveal = vertex;\n whenReady(graph, (ready) => ready.fitViewByPointPositions(corners(box), FIT_DURATION, FIT_PADDING));\n }\n\n // Primed first, so every `whenReady` below runs with `isReady` already answering true.\n isReady(graph);\n const painted = whenReady(graph, (ready) => {\n ready.setConfigPartial(appearance(look, host));\n ready.render();\n });\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 // Inside `whenReady`: cosmos.gl makes its canvas with the device, which is asynchronous.\n const listening = whenReady(graph, () => {\n host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n });\n store.report(store.getOptions().simulate && graph.isSimulationRunning ? \"running\" : \"settled\");\n frameExtent(last);\n schedule();\n\n return {\n graph,\n resident,\n composition: () => composition,\n repaint() {\n dirty.paint = true;\n schedule();\n },\n hit(shape) {\n if (!isReady(graph)) return [];\n const found = \"rect\" in shape ? graph.findPointsInRect(shape.rect) : graph.findPointsInPolygon(shape.polygon);\n return Array.from(found);\n },\n zoomBy(factor) {\n whenReady(graph, (ready) => ready.setZoomLevel(ready.getZoomLevel() * factor, 220));\n },\n fit() {\n const extent = store.getSnapshot().matrix?.extent;\n whenReady(graph, (ready) =>\n extent ? ready.fitViewByPointPositions(corners(extent), FIT_DURATION, FIT_PADDING) : ready.fitView(FIT_DURATION, FIT_PADDING),\n );\n },\n pause: () => whenReady(graph, (ready) => ready.pause()),\n resume() {\n const settled = store.getSnapshot().motion === \"settled\";\n whenReady(graph, (ready) => (settled ? ready.start(REHEAT) : ready.unpause()));\n },\n restart() {\n store.pin([]);\n whenReady(graph, (ready) => ready.start(1));\n },\n unpin() {\n if (store.getSnapshot().pinned.length === 0) return;\n store.pin([]);\n whenReady(graph, (ready) => ready.start(REHEAT));\n },\n reveal,\n frameBox(box, { duration = FIT_DURATION, padding = FIT_PADDING } = {}) {\n whenReady(graph, (ready) => ready.fitViewByPointPositions(corners(box), duration, padding));\n },\n frameSelection() {\n const indices = resident().indicesOf(store.getSnapshot().selection?.vertices ?? []);\n if (indices.length > 0) whenReady(graph, (ready) => ready.fitViewByPointIndices(indices, FIT_DURATION, 0.25));\n },\n clear,\n destroy() {\n unsubscribe();\n if (frame) cancelAnimationFrame(frame);\n painted();\n listening();\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\nconst EMPTY: Resident = {\n size: 0,\n indexOf: () => undefined,\n at: () => undefined,\n indicesOf: () => [],\n verticesAt: () => [],\n};\n"],"names":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","corners","box","createRenderer","host","store","events","fail","message","hasWebGL","sim","resolveSim","hovering","dragging","reported","progress","value","bucket","compose","createComposer","composition","look","resolveLook","lookPatch","dirty","frame","framed","pendingReveal","last","lastOptions","resident","EMPTY","viewport","height","width","isReady","graph","ax","ay","bx","by","view","observe","camera","Graph","forces","_a","index","vertex","focusOn","clear","error","schedule","whenReady","draw","ready","snapshot","options","changed","next","_b","reveal","drawn","buffers","paint","appearance","pinned","_c","frameExtent","extent","unsubscribe","applyForces","patch","simulate","moved","key","around","matrix","address","tileOfDense","denseOf","painted","onLost","event","listening","shape","found","factor","settled","duration","padding","indices","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 type { Box } from \"@fossil-lang/corpus\";\nimport type { Resident, VertexId } from \"../core/resident\";\nimport { denseOf } from \"../core/resident\";\nimport type { GraphSnapshot, GraphStore } from \"../core/store\";\nimport { tileOfDense, type Viewport } from \"../core/tile-matrix\";\nimport type { GraphCommands } from \"../core/types\";\nimport { createComposer, type Composition } from \"./compose\";\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 /** A new composition was uploaded. */\n onComposed?: (composition: Composition) => 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 resident(): Resident;\n composition(): Composition | null;\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\nconst corners = (box: Box) => [box.x, box.y, box.x + box.w, box.y + box.h];\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 change of visible tiles recomposes, and dirties positions, links and the per-point arrays;\n * - a look or a theme change dirties 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 * - a snapshot that changed none of those schedules nothing.\n *\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 * a drag needs none, since cosmos.gl moves the dragged point itself. 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 const compose = createComposer();\n let composition: Composition | null = null;\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { compose: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let destroyed = false;\n let framed: GraphSnapshot[\"matrix\"] = null;\n let pendingReveal: VertexId | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const resident = () => composition?.resident ?? EMPTY;\n\n const viewport = (): { view: Viewport; perPixel: number } | null => {\n const { height, width } = host.getBoundingClientRect();\n if (!graph.isReady || width === 0 || height === 0) return null;\n const [ax, ay] = graph.screenToSpacePosition([0, 0]);\n const [bx, by] = graph.screenToSpacePosition([width, height]);\n const view = { xMin: Math.min(ax, bx), yMin: Math.min(ay, by), xMax: Math.max(ax, bx), yMax: Math.max(ay, by) };\n return { view, perPixel: (view.xMax - view.xMin) / width };\n };\n const observe = () => {\n const camera = viewport();\n if (camera) store.setViewport(camera.view);\n };\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 matrix arrives.\n // `rescalePositions: false` because the corpus's coordinates are the camera's — a rescale\n // between them means the cull and the viewport describe different places.\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: () => {\n observe();\n events.onFrame?.();\n },\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(resident().at(index) ?? null);\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 === null ? undefined : resident().at(dragging);\n dragging = null;\n if (vertex !== undefined) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => {\n const vertex = resident().at(index);\n if (vertex !== undefined) focusOn(vertex, index);\n },\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 options = store.getOptions();\n let changed = false;\n if (dirty.compose && snapshot.matrix) {\n dirty.compose = false;\n const next = compose({\n matrix: snapshot.matrix,\n typeIndex: snapshot.typeIndex,\n binding: snapshot.binding,\n modeColumn: snapshot.modeColumn,\n domain: snapshot.domain,\n visible: snapshot.visible,\n cached: snapshot.cached,\n perPixel: viewport()?.perPixel ?? 0,\n });\n if (next) {\n composition = next;\n graph.setPointPositions(next.positions, true);\n graph.setLinks(next.links);\n dirty.paint = true;\n dirty.state = true;\n dirty.pinned = true;\n changed = true;\n events.onComposed?.(next);\n if (pendingReveal !== null && next.resident.indexOf(pendingReveal) !== undefined) {\n const vertex = pendingReveal;\n pendingReveal = null;\n queueMicrotask(() => reveal(vertex));\n }\n }\n const drawn = next && { marks: next.marks, represented: next.represented, domain: next.domain, tally: next.tally };\n store.reportDrawn(snapshot.visible, drawn);\n }\n if (dirty.paint && composition) {\n dirty.paint = false;\n const buffers = paint(composition, 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.setLinkWidths(buffers.linkWidths);\n graph.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && composition) {\n dirty.state = false;\n const drawn = composition.resident;\n graph.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? drawn.indicesOf(snapshot.selection.vertices) : undefined,\n focusedPointIndex: snapshot.focus === null ? undefined : drawn.indexOf(snapshot.focus),\n });\n }\n if (dirty.pinned && composition) {\n dirty.pinned = false;\n const pinned = composition.resident.indicesOf(snapshot.pinned);\n graph.setPinnedPoints(pinned.length > 0 ? pinned : null);\n }\n if (changed) graph.render();\n events.onFrame?.();\n }\n\n const frameExtent = (snapshot: GraphSnapshot) => {\n const extent = snapshot.matrix?.extent;\n if (!extent || snapshot.matrix === framed) return;\n framed = snapshot.matrix;\n graph.setConfigPartial({ spaceSize: Math.max(extent.w, extent.h) });\n graph.fitViewByPointPositions(corners(extent), 0, FIT_PADDING);\n void graph.ready.then(() => {\n if (!destroyed) observe();\n });\n };\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n frameExtent(snapshot);\n if (snapshot.visible !== last.visible || snapshot.binding !== last.binding || snapshot.domain !== last.domain) {\n dirty.compose = true;\n }\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.compose || 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, index: number): void {\n const drawn = resident();\n const around = drawn.verticesAt(graph.getNeighboringPointIndices(index));\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 /** Centre and select one vertex; one that is not drawn is framed by its tile first, then revealed. */\n function reveal(vertex: VertexId): void {\n const index = resident().indexOf(vertex);\n if (index !== undefined) {\n focusOn(vertex, index);\n graph.zoomToPointByIndex(index, 500, 5, true);\n return;\n }\n const matrix = store.getSnapshot().matrix;\n const address = matrix ? tileOfDense(matrix, denseOf(vertex)) : null;\n const box = address && matrix?.tileMatrices[address.z]?.tiles[address.tile]?.bbox;\n if (!box) return;\n pendingReveal = vertex;\n graph.fitViewByPointPositions(corners(box), FIT_DURATION, FIT_PADDING);\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 frameExtent(last);\n schedule();\n\n return {\n graph,\n resident,\n composition: () => composition,\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().matrix?.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,\n frameBox(box, { duration = FIT_DURATION, padding = FIT_PADDING } = {}) {\n graph.fitViewByPointPositions(corners(box), duration, padding);\n },\n frameSelection() {\n const indices = resident().indicesOf(store.getSnapshot().selection?.vertices ?? []);\n if (indices.length > 0) graph.fitViewByPointIndices(indices, 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\nconst EMPTY: Resident = { size: 0, indexOf: () => undefined, at: () => undefined, indicesOf: () => [], verticesAt: () => [] };\n"],"names":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","corners","box","createRenderer","host","store","events","fail","message","hasWebGL","sim","resolveSim","live","hovering","dragging","reported","progress","value","bucket","compose","createComposer","composition","look","resolveLook","lookPatch","dirty","frame","destroyed","framed","pendingReveal","last","lastOptions","resident","EMPTY","viewport","height","width","graph","ax","ay","bx","by","view","observe","camera","Graph","forces","_a","_alpha","index","position","_b","event","vertex","focusOn","clear","error","schedule","draw","snapshot","options","changed","next","reveal","drawn","buffers","paint","appearance","pinned","_c","frameExtent","extent","unsubscribe","applyForces","run","patch","moved","key","alpha","around","matrix","address","tileOfDense","denseOf","onLost","shape","found","factor","duration","padding","indices","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.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "Kanzo graph view — a tileset over a fossil corpus's scan, 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",
@@ -29,8 +29,8 @@
29
29
  "@fossil-lang/corpus": "^0.3.0-alpha.14",
30
30
  "lucide-react": ">=1",
31
31
  "react": "^19.0.0",
32
- "@kanzo-tech/mosaic": "0.13.1",
33
- "@kanzo-tech/ui": "0.13.1"
32
+ "@kanzo-tech/mosaic": "0.14.0",
33
+ "@kanzo-tech/ui": "0.14.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@cosmos.gl/graph": "^3.4.0",
@@ -46,8 +46,26 @@
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.13.1"
49
+ "@kanzo-tech/mosaic": "0.14.0"
50
50
  },
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`; budget set just above so real growth trips the gate.",
52
+ "size-limit": [
53
+ {
54
+ "name": "root barrel (JS)",
55
+ "path": "dist/index.js",
56
+ "limit": "19.5 kB",
57
+ "ignore": [
58
+ "react",
59
+ "react-dom",
60
+ "react/jsx-runtime",
61
+ "@cosmos.gl/graph",
62
+ "@fossil-lang/corpus",
63
+ "@kanzo-tech/mosaic",
64
+ "@kanzo-tech/ui",
65
+ "lucide-react"
66
+ ]
67
+ }
68
+ ],
51
69
  "repository": {
52
70
  "type": "git",
53
71
  "url": "git+https://github.com/Kanzo-Tech/ui.git",
@@ -60,6 +78,7 @@
60
78
  "scripts": {
61
79
  "build": "vite build",
62
80
  "typecheck": "tsc --noEmit",
63
- "test": "vitest run"
81
+ "test": "vitest run",
82
+ "size": "size-limit"
64
83
  }
65
84
  }
@@ -1,35 +0,0 @@
1
- import { Graph } from '@cosmos.gl/graph';
2
- /**
3
- * **Every write into cosmos.gl goes through here, because a non-null instance is not a usable one.**
4
- *
5
- * cosmos.gl 3.x builds its device asynchronously. The constructor returns immediately and
6
- * `graphRef.current` is set, but for tens of milliseconds — longer when several graphs mount on one
7
- * page — the instance has no points, no links and no config to change. What happens then is not one
8
- * failure mode but two, and the quiet one is worse:
9
- *
10
- * - `setPointPositions` **throws** `Cannot set properties of undefined (setting 'shouldSkipRescale')`.
11
- * React swallows it into the effect boundary, so it reaches the console and nothing else.
12
- * - `setPointColors`, `setPointSizes`, `setConfigPartial` and `fitViewByPointPositions` **do not**.
13
- * They raise a dirty flag on something that is not there and return, so the picture is simply
14
- * never uploaded: a blank canvas beside a badge reporting a full slice, with `onFailure` silent
15
- * and nothing in the console at all.
16
- *
17
- * Measured on `/docs/graph`, where three graphs mount together and none of them drew a single point.
18
- * Upstream states the contract in its own `.d.ts` for `findPointsInRect` and `findPointsInPolygon`
19
- * — *must only be called when the graph is ready* — and it holds for every setter too.
20
- *
21
- * **The rule is a helper rather than five `await`s** because it was broken at five call sites in
22
- * four modules, which is what `CONVENTIONS.md` means by a rule that has to become a test.
23
- * `when-ready.test.ts` is that test, and it reads the source rather than the behaviour.
24
- *
25
- * **`ready` has no failure path.** When the device cannot be made, cosmos.gl does not reject — the
26
- * promise simply never settles, so `apply` never runs and the canvas stays empty. That is the state
27
- * `hasWebGL()` in `use-renderer.ts` probes for before any of this, and it is why this returns a
28
- * cancel rather than being awaited: nothing here may hold a caller open.
29
- *
30
- * @returns a cancel. Call it from an effect's cleanup — during a pan the slices arrive faster than
31
- * a frame, and every one but the last is superseded before it could have been drawn.
32
- */
33
- export declare function whenReady(graph: Graph, apply: (graph: Graph) => void): () => void;
34
- export declare function isReady(graph: Graph): boolean;
35
- //# sourceMappingURL=when-ready.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"when-ready.d.ts","sourceRoot":"","sources":["../../src/render/when-ready.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI,CAQjF;AAeD,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAI7C"}