@graphysdk/geom-sankey 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,611 @@
1
+ import { Dataset as H, Geom as B, GeomPath as U, GeomRect as X, Stat as R, UserInputError as j, createValueFormatter as z, defineGeomRenderer as q, defineGeomStyleTarget as J, readVariableName as m, toPaintColor as O, toPercent as b, token as N, useGraphLocale as Z, usePaintDefs as I, useSceneSelector as Q } from "@graphysdk/react";
2
+ import { sankey as ee, sankeyCenter as te, sankeyJustify as re, sankeyLeft as ne, sankeyRight as ae } from "d3-sankey";
3
+ import { useMemo as T } from "react";
4
+ import { Fragment as Y, jsx as g, jsxs as C } from "react/jsx-runtime";
5
+ var i = {
6
+ kind: "sankeyKind",
7
+ nodeName: "sankeyNodeName",
8
+ observationKey: "sankeyObservationKey",
9
+ nodeKey: "sankeyNodeKey",
10
+ targetKey: "sankeyTargetKey",
11
+ x0: "sankeyX0",
12
+ x1: "sankeyX1",
13
+ y0: "sankeyY0",
14
+ y1: "sankeyY1",
15
+ targetY0: "sankeyTargetY0",
16
+ targetY1: "sankeyTargetY1"
17
+ }, k = (e, t) => {
18
+ const n = e[t];
19
+ return typeof n == "number" && Number.isFinite(n) ? n : null;
20
+ }, L = (e) => {
21
+ const t = e[i.observationKey], n = e[i.nodeKey], a = k(e, i.x0), o = k(e, i.x1), r = k(e, i.y0), s = k(e, i.y1);
22
+ if (typeof t != "string" || typeof n != "string" || a === null || o === null || r === null || s === null) return null;
23
+ switch (e[i.kind]) {
24
+ case "node":
25
+ return {
26
+ kind: "node",
27
+ observation: e,
28
+ key: t,
29
+ nodeKey: n,
30
+ x0: a,
31
+ x1: o,
32
+ y0: r,
33
+ y1: s
34
+ };
35
+ case "flow": {
36
+ const l = k(e, i.targetY0), u = k(e, i.targetY1), c = e[i.targetKey];
37
+ return l === null || u === null || typeof c != "string" ? null : {
38
+ kind: "flow",
39
+ observation: e,
40
+ key: t,
41
+ nodeKey: n,
42
+ targetKey: c,
43
+ x0: a,
44
+ x1: o,
45
+ y0: r,
46
+ y1: s,
47
+ targetY0: l,
48
+ targetY1: u
49
+ };
50
+ }
51
+ default:
52
+ return null;
53
+ }
54
+ }, P = /* @__PURE__ */ new WeakMap(), A = (e) => {
55
+ const t = P.get(e);
56
+ if (t !== void 0) return t;
57
+ const n = [], a = [];
58
+ for (const r of e) {
59
+ const s = L(r);
60
+ s?.kind === "node" && n.push(s), s?.kind === "flow" && a.push(s);
61
+ }
62
+ const o = {
63
+ nodes: n,
64
+ flows: a
65
+ };
66
+ return P.set(e, o), o;
67
+ }, _ = (e, t) => e.nodeKey === t.nodeKey || e.targetKey === t.nodeKey, oe = (e) => e * e * (3 - 2 * e), M = (e, t) => {
68
+ const n = oe(t);
69
+ return {
70
+ top: e.y0 + (e.targetY0 - e.y0) * n,
71
+ bottom: e.y1 + (e.targetY1 - e.y1) * n
72
+ };
73
+ }, se = (e, t) => {
74
+ const n = e.x1 - e.x0;
75
+ if (n <= 0 || t.x < e.x0 || t.x > e.x1) return !1;
76
+ const { top: a, bottom: o } = M(e, (t.x - e.x0) / n);
77
+ return t.y >= a && t.y <= o;
78
+ }, W = (e, t) => {
79
+ const n = (u) => u * t.width, a = (u) => u * t.height, o = n(e.x0), r = n(e.x1), s = n(e.x0 + (e.x1 - e.x0) / 3), l = n(e.x0 + (e.x1 - e.x0) * 2 / 3);
80
+ return [
81
+ `M${o},${a(e.y0)}`,
82
+ `C${s},${a(e.y0)} ${l},${a(e.targetY0)} ${r},${a(e.targetY0)}`,
83
+ `L${r},${a(e.targetY1)}`,
84
+ `C${l},${a(e.targetY1)} ${s},${a(e.y1)} ${o},${a(e.y1)}`,
85
+ "Z"
86
+ ].join("");
87
+ }, ie = 0.018, le = 0.03, ue = {
88
+ justify: re,
89
+ left: ne,
90
+ right: ae,
91
+ center: te
92
+ }, ce = (e, t) => {
93
+ const n = ye(e);
94
+ if (n.length === 0) return {
95
+ nodes: [],
96
+ flows: []
97
+ };
98
+ const a = [...new Set(n.flatMap((r) => [r.source, r.target]))], o = ee().nodeId((r) => r.key).nodeAlign(ue[t]).nodeWidth(ie).nodePadding(le).extent([[0, 0], [1, 1]])({
99
+ nodes: a.map((r) => ({ key: r })),
100
+ links: n.map((r) => ({
101
+ source: r.source,
102
+ target: r.target,
103
+ value: r.value,
104
+ link: r
105
+ }))
106
+ });
107
+ return {
108
+ nodes: o.nodes.map((r) => ({
109
+ key: r.key,
110
+ value: r.value ?? 0,
111
+ x0: p(r.x0),
112
+ x1: p(r.x1),
113
+ y0: p(r.y0),
114
+ y1: p(r.y1)
115
+ })),
116
+ flows: o.links.map((r) => {
117
+ const s = r.source, l = r.target, u = (r.width ?? 0) / 2;
118
+ return {
119
+ link: r.link,
120
+ x0: p(s.x1),
121
+ x1: p(l.x0),
122
+ y0: p((r.y0 ?? 0) - u),
123
+ y1: p((r.y0 ?? 0) + u),
124
+ targetY0: p((r.y1 ?? 0) - u),
125
+ targetY1: p((r.y1 ?? 0) + u)
126
+ };
127
+ })
128
+ };
129
+ }, p = (e) => Math.min(1, Math.max(0, e ?? 0)), ye = (e) => {
130
+ const t = /* @__PURE__ */ new Map(), n = (a, o) => {
131
+ const r = /* @__PURE__ */ new Set(), s = [a];
132
+ for (; s.length > 0; ) {
133
+ const l = s.pop();
134
+ if (l === o) return !0;
135
+ r.has(l) || (r.add(l), s.push(...t.get(l) ?? []));
136
+ }
137
+ return !1;
138
+ };
139
+ return e.filter((a) => t.get(a.source)?.has(a.target) === !0 ? !0 : n(a.target, a.source) ? !1 : (t.set(a.source, (t.get(a.source) ?? /* @__PURE__ */ new Set()).add(a.target)), !0));
140
+ }, D = /* @__PURE__ */ new Set(["node"]), G = ["color", "alpha"], de = [
141
+ "justify",
142
+ "left",
143
+ "right",
144
+ "center"
145
+ ], ge = class extends R {
146
+ constructor(...e) {
147
+ super(...e), this.type = "sankey", this.computedVariables = D;
148
+ }
149
+ computeStat({ data: e, mapping: t, params: n }) {
150
+ const a = xe(e, t);
151
+ return a === null ? {
152
+ data: e,
153
+ mapping: {}
154
+ } : (fe(e, a), {
155
+ data: Ne(e, a, me(n)),
156
+ mapping: {
157
+ node: i.nodeName,
158
+ ...ve(t, a)
159
+ }
160
+ });
161
+ }
162
+ }, ve = (e, t) => {
163
+ const n = {};
164
+ for (const a of G) {
165
+ const o = he(a, e[a], t);
166
+ o !== null && (n[a] = o);
167
+ }
168
+ return n;
169
+ }, he = (e, t, { sourceVariable: n, targetVariable: a }) => {
170
+ if (t === void 0) return e === "color" ? i.nodeKey : null;
171
+ const o = m(t);
172
+ return o === n ? i.nodeKey : o === a ? i.targetKey : null;
173
+ }, pe = (e) => de.includes(e), me = (e) => {
174
+ const t = e?.align;
175
+ return pe(t) ? t : "justify";
176
+ }, $ = (e, t) => e === null ? null : e instanceof Date ? t.type === "year" ? String(e.getUTCFullYear()) : e.toISOString() : String(e), fe = (e, { valueVariable: t }) => {
177
+ const n = e.getType(t);
178
+ if (!(e.size() === 0 || n === "numeric"))
179
+ throw new j({
180
+ code: "INCOMPATIBLE_TYPE",
181
+ message: `'sankey' stat requires a numeric 'value' (got '${n}' for variable '${t}')`,
182
+ context: {
183
+ aesthetic: "value",
184
+ variableName: t,
185
+ variableType: n
186
+ },
187
+ suggestion: "Map each flow's amount to 'value', declaring the column numeric if it holds whole years."
188
+ });
189
+ }, xe = (e, t) => {
190
+ const n = m(t.source), a = m(t.target), o = m(t.value);
191
+ return n === null || a === null || o === null || ![
192
+ n,
193
+ a,
194
+ o
195
+ ].every((r) => e.hasVariable(r)) ? null : {
196
+ sourceVariable: n,
197
+ targetVariable: a,
198
+ valueVariable: o
199
+ };
200
+ }, ke = (e, { sourceVariable: t, targetVariable: n, valueVariable: a }) => {
201
+ const o = e.getValues(t), r = e.getValues(n), s = e.getValues(a, { type: "numeric" }), l = e.getValueFormat(t), u = e.getValueFormat(n), c = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), y = [];
202
+ return o.forEach((v, h) => {
203
+ const S = r[h] ?? null, f = $(v, l), x = $(S, u);
204
+ if (f === null || x === null) return;
205
+ d.set(f, v), d.set(x, S);
206
+ const F = JSON.stringify([f, x]), V = c.get(F) ?? 0;
207
+ c.set(F, V + 1);
208
+ const K = s[h];
209
+ typeof K != "number" || !Number.isFinite(K) || K <= 0 || y.push({
210
+ source: f,
211
+ target: x,
212
+ value: K,
213
+ row: h,
214
+ occurrence: V
215
+ });
216
+ }), {
217
+ links: y,
218
+ names: d
219
+ };
220
+ }, w = (e, { sourceVariable: t, targetVariable: n }) => e.getType(t) === e.getType(n), be = (e, t, n, a) => {
221
+ const o = e.getType(t.sourceVariable);
222
+ return w(e, t) ? {
223
+ type: o,
224
+ values: n.map((r) => a.get(r) ?? null),
225
+ valueFormat: e.getValueFormat(t.sourceVariable)
226
+ } : {
227
+ type: "categorical",
228
+ values: [...n]
229
+ };
230
+ }, Se = (e, t, n, a, o) => e === n.valueVariable ? a.nodes.map((r) => r.value) : e === n.sourceVariable && w(t, n) ? a.nodes.map((r) => o.get(r.key) ?? null) : null, Ne = (e, t, n) => {
231
+ const { links: a, names: o } = ke(e, t), r = ce(a, n), s = r.nodes.length, l = (y) => [...y, ...Array.from({ length: s }, () => null)], u = e.getVariableNames(), c = Object.fromEntries(u.map((y) => {
232
+ const v = e.getValues(y), h = r.flows.map(({ link: x }) => v[x.row] ?? null), S = Se(y, e, t, r, o), f = S === null ? l(h) : [...h, ...S];
233
+ return [y, {
234
+ type: e.getType(y),
235
+ values: f,
236
+ valueFormat: e.getValueFormat(y)
237
+ }];
238
+ })), d = [...r.flows.map(({ link: y }) => y.source), ...r.nodes.map(({ key: y }) => y)];
239
+ return new H({
240
+ ...c,
241
+ ...Ae(r),
242
+ [i.nodeName]: be(e, t, d, o)
243
+ });
244
+ }, Ae = (e) => {
245
+ const t = e.flows.map(({ link: l, ...u }) => ({
246
+ [i.kind]: "flow",
247
+ [i.observationKey]: JSON.stringify([
248
+ "flow",
249
+ l.source,
250
+ l.target,
251
+ l.occurrence
252
+ ]),
253
+ [i.nodeKey]: l.source,
254
+ [i.targetKey]: l.target,
255
+ [i.x0]: u.x0,
256
+ [i.x1]: u.x1,
257
+ [i.y0]: u.y0,
258
+ [i.y1]: u.y1,
259
+ [i.targetY0]: u.targetY0,
260
+ [i.targetY1]: u.targetY1
261
+ })), n = e.nodes.map((l) => ({
262
+ [i.kind]: "node",
263
+ [i.observationKey]: JSON.stringify(["node", l.key]),
264
+ [i.nodeKey]: l.key,
265
+ [i.targetKey]: l.key,
266
+ [i.x0]: l.x0,
267
+ [i.x1]: l.x1,
268
+ [i.y0]: l.y0,
269
+ [i.y1]: l.y1,
270
+ [i.targetY0]: null,
271
+ [i.targetY1]: null
272
+ })), a = [...t, ...n], o = (l) => a.map((u) => u[l]), r = (l) => ({
273
+ type: "categorical",
274
+ values: o(l)
275
+ }), s = (l) => ({
276
+ type: "numeric",
277
+ values: o(l)
278
+ });
279
+ return {
280
+ [i.kind]: r(i.kind),
281
+ [i.observationKey]: r(i.observationKey),
282
+ [i.nodeKey]: r(i.nodeKey),
283
+ [i.targetKey]: r(i.targetKey),
284
+ [i.x0]: s(i.x0),
285
+ [i.x1]: s(i.x1),
286
+ [i.y0]: s(i.y0),
287
+ [i.y1]: s(i.y1),
288
+ [i.targetY0]: s(i.targetY0),
289
+ [i.targetY1]: s(i.targetY1)
290
+ };
291
+ }, Ke = 0.4, Oe = 0.65, Te = 12, Ye = 3, Ce = {}, Le = {
292
+ fill: "paint",
293
+ fillAlpha: "unitInterval",
294
+ alpha: "unitInterval",
295
+ stroke: "color",
296
+ strokeWidth: "pixels"
297
+ }, Ee = {
298
+ fontFamily: "fontFamily",
299
+ fontSize: "pixels",
300
+ fontWeight: "fontWeight",
301
+ textColor: "color",
302
+ textOutlineColor: "color",
303
+ textOutlineWidth: "pixels"
304
+ }, Fe = class extends B {
305
+ constructor(...e) {
306
+ super(...e), this.type = "sankey", this.defaultParams = { align: "justify" }, this.defaultStat = new ge(), this.aesthetics = [
307
+ {
308
+ kind: "data",
309
+ name: "source",
310
+ required: !0
311
+ },
312
+ {
313
+ kind: "data",
314
+ name: "target",
315
+ required: !0
316
+ },
317
+ {
318
+ kind: "data",
319
+ name: "value",
320
+ required: !0
321
+ },
322
+ {
323
+ kind: "data",
324
+ name: "node"
325
+ },
326
+ {
327
+ kind: "visual",
328
+ name: "color"
329
+ },
330
+ {
331
+ kind: "visual",
332
+ name: "alpha"
333
+ }
334
+ ], this.identityKey = { variable: i.observationKey }, this.supportedPositions = ["identity"], this.supportedCoordTypes = ["cartesian"], this.legend = { defaultPosition: "none" }, this.spatialKind = "render-hit-test", this.highlightStrategy = "observation-rerender", this.tooltip = [
335
+ {
336
+ aes: "node",
337
+ heading: !0
338
+ },
339
+ { aes: "target" },
340
+ { aes: "value" }
341
+ ], this.styleTarget = J({
342
+ observation: {
343
+ vocabulary: Ce,
344
+ aesthetics: {
345
+ fill: "color",
346
+ alpha: "alpha"
347
+ },
348
+ rest: {
349
+ fill: N("geom"),
350
+ fillAlpha: Ke
351
+ },
352
+ hovered: { fillAlpha: Oe }
353
+ },
354
+ parts: {
355
+ node: {
356
+ vocabulary: Le,
357
+ aesthetics: {
358
+ fill: "color",
359
+ alpha: "alpha"
360
+ },
361
+ rest: {
362
+ fill: N("geom"),
363
+ fillAlpha: 1,
364
+ alpha: 1,
365
+ stroke: N("graphBackground"),
366
+ strokeWidth: 0
367
+ }
368
+ },
369
+ label: {
370
+ vocabulary: Ee,
371
+ rest: {
372
+ fontSize: Te,
373
+ fontWeight: 500,
374
+ textColor: N("textPrimary"),
375
+ textOutlineColor: N("graphBackground"),
376
+ textOutlineWidth: Ye
377
+ }
378
+ }
379
+ }
380
+ }), this.resolveValueSource = (t) => t.value ?? null, this.validateMapping = ({ mapping: t, computedVariables: n }) => {
381
+ if (!n.has("node")) return [{
382
+ code: "MISSING_STAT_OUTPUT",
383
+ message: "sankey geom lays its flows out in the 'sankey' stat; remove the layer's stat"
384
+ }];
385
+ const a = [...D].filter((s) => t[s] !== void 0).map((s) => ({
386
+ code: "CONFLICTING_STAT_MAPPING",
387
+ message: `sankey stat computes '${s}' from 'source' and 'target'; remove its mapping`
388
+ })), o = [m(t.source), m(t.target)], r = G.flatMap((s) => {
389
+ const l = m(t[s]);
390
+ return l === null || o.includes(l) ? [] : [{
391
+ code: "UNSUPPORTED_MAPPING",
392
+ message: `sankey geom scales '${s}' by node; map it to the source or target column rather than '${l}'`
393
+ }];
394
+ });
395
+ return [...a, ...r];
396
+ }, this.resolveAnchorPosition = (t) => {
397
+ const n = L(t);
398
+ if (n === null) return null;
399
+ if (n.kind === "node") return {
400
+ x: (n.x0 + n.x1) / 2,
401
+ y: 1 - (n.y0 + n.y1) / 2
402
+ };
403
+ const { top: a, bottom: o } = M(n, 0.5);
404
+ return {
405
+ x: (n.x0 + n.x1) / 2,
406
+ y: 1 - (a + o) / 2
407
+ };
408
+ };
409
+ }
410
+ compile({ data: e }) {
411
+ return {
412
+ data: e,
413
+ mapping: {}
414
+ };
415
+ }
416
+ }, Ve = ({ layer: e, panelRect: t }) => {
417
+ const { nodes: n, flows: a } = A(e.data), o = (s) => s * t.width, r = (s) => s * t.height;
418
+ return [...a.map((s) => ({
419
+ kind: "region",
420
+ pathData: W(s, t)
421
+ })), ...n.map((s) => ({
422
+ kind: "region",
423
+ pathData: `M${o(s.x0)},${r(s.y0)}H${o(s.x1)}V${r(s.y1)}H${o(s.x0)}Z`
424
+ }))];
425
+ }, Pe = ({ flows: e, size: t, source: n, styleReaders: a, isHovered: o = !1, shouldAnimateTransitions: r = !1 }) => {
426
+ const s = o ? "hovered" : void 0, l = T(() => e.map((d) => a.get("fill", d.observation, s) ?? "transparent"), [
427
+ e,
428
+ a,
429
+ s
430
+ ]), { fillFor: u, defs: c } = I({ paints: l });
431
+ return /* @__PURE__ */ C(Y, { children: [c, e.map((d, y) => {
432
+ const v = l[y], h = a.get("stroke", d.observation, s);
433
+ return /* @__PURE__ */ g(U, {
434
+ "data-testid": "sankey-flow",
435
+ d: W(d, t),
436
+ source: n,
437
+ fill: v === void 0 ? void 0 : u(v),
438
+ opacity: a.get("alpha", d.observation, s),
439
+ fillOpacity: a.get("fillAlpha", d.observation, s),
440
+ stroke: h === void 0 ? void 0 : O(h),
441
+ strokeOpacity: a.get("strokeAlpha", d.observation, s),
442
+ shouldAnimateTransitions: r
443
+ }, d.key);
444
+ })] });
445
+ }, _e = 6, $e = (e) => {
446
+ const t = (e.y0 + e.y1) / 2;
447
+ return (e.x0 + e.x1) / 2 < 0.5 ? {
448
+ x: e.x1,
449
+ y: t,
450
+ offsetX: _e,
451
+ textAnchor: "start"
452
+ } : {
453
+ x: e.x0,
454
+ y: t,
455
+ offsetX: -6,
456
+ textAnchor: "end"
457
+ };
458
+ }, Ie = ({ nodes: e, valueFormat: t, styleReaders: n, isHovered: a = !1 }) => {
459
+ const o = a ? "hovered" : void 0, r = n.part("label"), s = Z(), l = Q((c) => c.config.numberFormat), u = T(() => z({
460
+ valueFormat: t,
461
+ locale: s,
462
+ numberFormat: l
463
+ }), [
464
+ t,
465
+ s,
466
+ l
467
+ ]);
468
+ return /* @__PURE__ */ g("g", {
469
+ pointerEvents: "none",
470
+ children: e.map((c) => {
471
+ const d = c.observation[i.nodeName];
472
+ if (d == null) return null;
473
+ const y = $e(c), v = r?.get("textColor", c.observation, o), h = r?.get("textOutlineColor", c.observation, o);
474
+ return /* @__PURE__ */ g("text", {
475
+ "data-testid": "sankey-label",
476
+ x: b(y.x),
477
+ y: b(y.y),
478
+ dx: y.offsetX,
479
+ textAnchor: y.textAnchor,
480
+ dominantBaseline: "central",
481
+ fontFamily: r?.get("fontFamily", c.observation, o),
482
+ fontSize: r?.get("fontSize", c.observation, o),
483
+ fontWeight: r?.get("fontWeight", c.observation, o),
484
+ fill: v === void 0 ? void 0 : O(v),
485
+ stroke: h === void 0 ? void 0 : O(h),
486
+ strokeWidth: r?.get("textOutlineWidth", c.observation, o),
487
+ strokeLinejoin: "round",
488
+ paintOrder: "stroke",
489
+ children: u(d, c.observation)
490
+ }, c.key);
491
+ })
492
+ });
493
+ }, Me = ({ nodes: e, styleReaders: t, isHovered: n = !1, shouldAnimateTransitions: a = !1 }) => {
494
+ const o = n ? "hovered" : void 0, r = t.part("node"), s = T(() => e.map((c) => r?.get("fill", c.observation, o) ?? "transparent"), [
495
+ e,
496
+ r,
497
+ o
498
+ ]), { fillFor: l, defs: u } = I({ paints: s });
499
+ return /* @__PURE__ */ C(Y, { children: [u, e.map((c, d) => {
500
+ const y = s[d], v = r?.get("stroke", c.observation, o);
501
+ return /* @__PURE__ */ g(X, {
502
+ "data-testid": "sankey-node",
503
+ x: b(c.x0),
504
+ y: b(c.y0),
505
+ width: b(c.x1 - c.x0),
506
+ height: b(c.y1 - c.y0),
507
+ fill: y === void 0 ? void 0 : l(y),
508
+ opacity: r?.get("alpha", c.observation, o),
509
+ fillOpacity: r?.get("fillAlpha", c.observation, o),
510
+ stroke: v === void 0 ? void 0 : O(v),
511
+ strokeWidth: r?.get("strokeWidth", c.observation, o),
512
+ shouldAnimateTransitions: a
513
+ }, c.key);
514
+ })] });
515
+ }, We = { type: "text" }, E = ({ observations: e, layer: t, size: n, styleReaders: a, isHovered: o = !1, shouldAnimateTransitions: r = !1 }) => /* @__PURE__ */ C(Y, { children: [
516
+ /* @__PURE__ */ g(Pe, {
517
+ flows: e.flows,
518
+ size: n,
519
+ source: t,
520
+ styleReaders: a,
521
+ isHovered: o,
522
+ shouldAnimateTransitions: r
523
+ }),
524
+ /* @__PURE__ */ g(Me, {
525
+ nodes: e.nodes,
526
+ styleReaders: a,
527
+ isHovered: o,
528
+ shouldAnimateTransitions: r
529
+ }),
530
+ /* @__PURE__ */ g(Ie, {
531
+ nodes: e.nodes,
532
+ valueFormat: t.data.hasVariable(i.nodeName) ? t.data.getValueFormat(i.nodeName) : We,
533
+ styleReaders: a,
534
+ isHovered: o
535
+ })
536
+ ] }), De = ({ layer: e, size: t, styleReaders: n }) => /* @__PURE__ */ g(E, {
537
+ observations: A(e.data),
538
+ layer: e,
539
+ size: t,
540
+ styleReaders: n
541
+ }), Ge = ({ layer: e }) => {
542
+ const { nodes: t, flows: n } = A(e.data), a = [...t].reverse(), o = [...n].reverse();
543
+ return (r) => {
544
+ const s = a.find((u) => r.x >= u.x0 && r.x <= u.x1 && r.y >= u.y0 && r.y <= u.y1);
545
+ if (s !== void 0) return { key: s.key };
546
+ const l = o.find((u) => se(u, r));
547
+ return l === void 0 ? null : { key: l.key };
548
+ };
549
+ }, we = ({ layer: e, primary: t, size: n, styleReaders: a }) => {
550
+ const o = A(e.data), r = t.observation;
551
+ return /* @__PURE__ */ g("g", {
552
+ "data-testid": "hovered-observations",
553
+ children: /* @__PURE__ */ g(E, {
554
+ observations: T(() => He(o, r), [o, r]),
555
+ layer: e,
556
+ size: n,
557
+ styleReaders: a,
558
+ isHovered: !0
559
+ })
560
+ });
561
+ }, He = (e, t) => {
562
+ const n = L(t);
563
+ if (n === null) return {
564
+ nodes: [],
565
+ flows: []
566
+ };
567
+ if (n.kind === "node") {
568
+ const a = e.flows.filter((r) => _(r, n)), o = new Set(a.flatMap((r) => [r.nodeKey, r.targetKey]));
569
+ return {
570
+ nodes: e.nodes.filter((r) => o.has(r.nodeKey)),
571
+ flows: a
572
+ };
573
+ }
574
+ return {
575
+ nodes: e.nodes.filter((a) => _(n, a)),
576
+ flows: [n]
577
+ };
578
+ }, Be = ({ layer: e, size: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(E, {
579
+ observations: A(e.data),
580
+ layer: e,
581
+ size: t,
582
+ styleReaders: n,
583
+ shouldAnimateTransitions: a
584
+ }), ze = q(new Fe(), {
585
+ coord: "cartesian",
586
+ swatchShape: "square",
587
+ render: ({ layer: e, panelRect: t, styleReaders: n, shouldAnimateTransitions: a }) => /* @__PURE__ */ g(Be, {
588
+ layer: e,
589
+ size: t,
590
+ styleReaders: n,
591
+ shouldAnimateTransitions: a
592
+ }),
593
+ renderHighlight: ({ layer: e, panelRect: t, styleReaders: n }) => /* @__PURE__ */ g(De, {
594
+ layer: e,
595
+ size: t,
596
+ styleReaders: n
597
+ }),
598
+ renderHover: ({ layer: e, primary: t, panelRect: n, styleReaders: a }) => /* @__PURE__ */ g(we, {
599
+ layer: e,
600
+ primary: t,
601
+ size: n,
602
+ styleReaders: a
603
+ }),
604
+ renderHoverCompanions: () => null,
605
+ hitTest: Ge,
606
+ getEditOutlineShapes: Ve
607
+ });
608
+ export {
609
+ Fe as SankeyGeom,
610
+ ze as sankey
611
+ };
@@ -0,0 +1,17 @@
1
+ import { GeomStyleReaders, SceneLayer } from '@graphysdk/react';
2
+ import { SankeyFlowObservation } from '../../utils/read-sankey';
3
+ export interface SankeyFlowsProps {
4
+ flows: readonly SankeyFlowObservation[];
5
+ /** The panel's size in pixels: a ribbon is a path, which has no percentage units. */
6
+ size: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ /** The layer the ribbons are drawn from, so a resize redraws them in place and only new data morphs them. */
11
+ source: SceneLayer;
12
+ styleReaders: GeomStyleReaders;
13
+ isHovered?: boolean;
14
+ shouldAnimateTransitions?: boolean;
15
+ }
16
+ /** Each flow as a filled ribbon, painted through the observations' readers. */
17
+ export declare const SankeyFlows: ({ flows, size, source, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyFlowsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { GeomStyleReaders, ValueFormat } from '@graphysdk/react';
2
+ import { SankeyNodeObservation } from '../../utils/read-sankey';
3
+ export interface SankeyLabelsProps {
4
+ nodes: readonly SankeyNodeObservation[];
5
+ /** The node names' format. */
6
+ valueFormat: ValueFormat;
7
+ styleReaders: GeomStyleReaders;
8
+ isHovered?: boolean;
9
+ }
10
+ /**
11
+ * Each node's name beside it, painted through the `label` part's readers. The outline, in the background's color
12
+ * by default, keeps a name legible where it crosses a flow.
13
+ */
14
+ export declare const SankeyLabels: ({ nodes, valueFormat, styleReaders, isHovered }: SankeyLabelsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { GeomStyleReaders } from '@graphysdk/react';
2
+ import { SankeyNodeObservation } from '../../utils/read-sankey';
3
+ export interface SankeyNodesProps {
4
+ nodes: readonly SankeyNodeObservation[];
5
+ styleReaders: GeomStyleReaders;
6
+ isHovered?: boolean;
7
+ shouldAnimateTransitions?: boolean;
8
+ }
9
+ /** Each node as its box, painted through the `node` part's readers. */
10
+ export declare const SankeyNodes: ({ nodes, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyNodesProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { GeomStyleReaders, SceneLayer } from '@graphysdk/react';
2
+ import { SankeyObservations } from '../../utils/read-sankey';
3
+ export interface SankeyPaintProps {
4
+ observations: SankeyObservations;
5
+ /** The layer the observations were read from: the node names' format, and what a ribbon morph is keyed to. */
6
+ layer: SceneLayer;
7
+ size: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ styleReaders: GeomStyleReaders;
12
+ isHovered?: boolean;
13
+ shouldAnimateTransitions?: boolean;
14
+ }
15
+ /** The flows, the nodes over their ends, and the names over both. */
16
+ export declare const SankeyPaint: ({ observations, layer, size, styleReaders, isHovered, shouldAnimateTransitions, }: SankeyPaintProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { EditOutlineShape, GeomEditOutlineShapesRendererInput } from '@graphysdk/react';
2
+ /** A node outlines as its box, a flow as its ribbon. */
3
+ export declare const getSankeyEditOutlineShapes: ({ layer, panelRect, }: GeomEditOutlineShapesRendererInput) => EditOutlineShape[];
@@ -0,0 +1,12 @@
1
+ import { GeomStyleReaders, SceneLayer } from '@graphysdk/react';
2
+ interface HighlightedObservationsProps {
3
+ layer: SceneLayer;
4
+ size: {
5
+ width: number;
6
+ height: number;
7
+ };
8
+ styleReaders: GeomStyleReaders;
9
+ }
10
+ /** Repaints the matched nodes and flows above the dimmed layer. */
11
+ export declare const HighlightedObservations: ({ layer, size, styleReaders }: HighlightedObservationsProps) => import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,3 @@
1
+ import { GeomRendererInput, RenderHitTester } from '@graphysdk/react';
2
+ /** Tests in unit space, in reverse paint order (nodes over flows, later flows over earlier), so the topmost answers. */
3
+ export declare const buildSankeyHitTester: ({ layer }: GeomRendererInput) => RenderHitTester;