@gen-epix/ui-phylogenetic-tree 2.0.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.
@@ -0,0 +1,537 @@
1
+ import { TreeUtil as e } from "../../utils/TreeUtil/index.js";
2
+ import { Box as t } from "@mui/material";
3
+ import { useCallback as n, useEffect as r, useImperativeHandle as i, useMemo as a, useRef as o, useState as s } from "react";
4
+ import { DevicePixelRatioService as c } from "@gen-epix/ui-core/classes/services/DevicePixelRatioService";
5
+ import { Subject as l } from "@gen-epix/ui-core/classes/Subject";
6
+ import { useScrollbarSize as u } from "@gen-epix/ui-core/hooks/useScrollbarSize";
7
+ import { useDimensions as d } from "@gen-epix/ui-core/hooks/useDimensions";
8
+ import { useSubscribable as f } from "@gen-epix/ui-core/hooks/useSubscribable";
9
+ import { jsx as p } from "react/jsx-runtime";
10
+ //#region ../../node_modules/.pnpm/use-debounce@10.1.1_react@19.2.7/node_modules/use-debounce/dist/index.module.js
11
+ function m(e, t, n, i) {
12
+ var s = this, c = o(null), l = o(0), u = o(0), d = o(null), f = o([]), p = o(), m = o(), h = o(e), g = o(!0), _ = o(), v = o();
13
+ h.current = e;
14
+ var y = typeof window < "u", b = !t && t !== 0 && y;
15
+ if (typeof e != "function") throw TypeError("Expected a function");
16
+ t = +t || 0;
17
+ var x = !!(n ||= {}).leading, S = !("trailing" in n) || !!n.trailing, C = !!n.flushOnExit && S, w = "maxWait" in n, T = "debounceOnServer" in n && !!n.debounceOnServer, E = w ? Math.max(+n.maxWait || 0, t) : null, D = a(function() {
18
+ var e = function(e) {
19
+ var t = f.current, n = p.current;
20
+ return f.current = p.current = null, l.current = e, u.current = u.current || e, m.current = h.current.apply(n, t);
21
+ }, n = function(e, t) {
22
+ b && cancelAnimationFrame(d.current), d.current = b ? requestAnimationFrame(e) : setTimeout(e, t);
23
+ }, r = function(e) {
24
+ if (!g.current) return !1;
25
+ var n = e - c.current;
26
+ return !c.current || n >= t || n < 0 || w && e - l.current >= E;
27
+ }, a = function(t) {
28
+ return d.current = null, S && f.current ? e(t) : (f.current = p.current = null, m.current);
29
+ }, o = function e() {
30
+ var i = Date.now();
31
+ if (x && u.current === l.current && D(), r(i)) return a(i);
32
+ if (g.current) {
33
+ var o = t - (i - c.current);
34
+ n(e, w ? Math.min(o, E - (i - l.current)) : o);
35
+ }
36
+ }, D = function() {
37
+ i && i({});
38
+ }, O = function() {
39
+ if (y || T) {
40
+ var i, a = Date.now(), u = r(a);
41
+ if (f.current = [].slice.call(arguments), p.current = s, c.current = a, C && !_.current && (_.current = function() {
42
+ globalThis.document?.visibilityState === "hidden" && v.current.flush();
43
+ }, (i = globalThis.document) == null || i.addEventListener == null || i.addEventListener("visibilitychange", _.current)), u) {
44
+ if (!d.current && g.current) return l.current = c.current, n(o, t), x ? e(c.current) : m.current;
45
+ if (w) return n(o, t), e(c.current);
46
+ }
47
+ return d.current || n(o, t), m.current;
48
+ }
49
+ };
50
+ return O.cancel = function() {
51
+ var e = d.current;
52
+ e && (b ? cancelAnimationFrame(d.current) : clearTimeout(d.current)), l.current = 0, f.current = c.current = p.current = d.current = null, e && i && i({});
53
+ }, O.isPending = function() {
54
+ return !!d.current;
55
+ }, O.flush = function() {
56
+ return d.current ? a(Date.now()) : m.current;
57
+ }, O;
58
+ }, [
59
+ x,
60
+ w,
61
+ t,
62
+ E,
63
+ S,
64
+ C,
65
+ b,
66
+ y,
67
+ T,
68
+ i
69
+ ]);
70
+ return v.current = D, r(function() {
71
+ return g.current = !0, function() {
72
+ var e;
73
+ C && v.current.flush(), _.current &&= ((e = globalThis.document) == null || e.removeEventListener == null || e.removeEventListener("visibilitychange", _.current), null), g.current = !1;
74
+ };
75
+ }, [C]), D;
76
+ }
77
+ //#endregion
78
+ //#region src/components/PhylogeneticTree/PhylogeneticTree.tsx
79
+ var h = ({ ancestorDotRadius: h, ariaLabel: g, backgroundColor: _, dimFn: v, fontFamily: y, headerHeight: b, highlightedNodeNamesSubject: x, initialViewState: S, itemHeight: C, leafDotRadius: w, linkedScrollDebounceDelayMs: T, maxScaleWidthPx: E, maxZoomLevel: D, maxZoomSpeed: O, minimumDistancePercentageToShowLabel: ee, minScaleWidthPx: te, minZoomLevel: ne, minZoomSpeed: re, nodeNameColors: ie, onCanvasChange: k, onLinkStateChange: ae, onPathClick: oe, onViewStateChange: A, panningThreshold: se, ref: ce, regularFillColorSupportLine: le, scaleColor: ue, scaleIncrements: de, scrollSubject: j, shouldShowDistances: fe, shouldShowSupportLinesWhenUnlinked: pe, sortedLeafNames: me, supportLineColorLinked: he, supportLineColorUnlinked: ge, tree: M, treeColor: _e, treeFont: ve, treePadding: N, visibleRangeSubject: P }) => {
80
+ let ye = u(), F = o(null), be = o(null), { dimensions: { height: xe, width: Se } } = d(be), [I, Ce] = s(), [L, R] = s(null), [z, we] = s(c.getInstance().data), [B, V] = s(!0), H = a(() => new l({
81
+ x: 0,
82
+ y: 0
83
+ }), []), U = a(() => new l(isNaN(S?.zoomLevel) ? 1 : S.zoomLevel), [S]), W = a(() => new l({
84
+ horizontal: isNaN(S?.horizontalScrollPosition) ? 0 : S.horizontalScrollPosition,
85
+ vertical: isNaN(S?.verticalScrollPosition) ? 0 : S.verticalScrollPosition
86
+ }), [S]), G = Se, K = Math.max(0, xe - b), Te = Math.max(0, xe), q = G - 2 * N, J = M?.maxBranchLength ? q / M.maxBranchLength.toNumber() : null, Y = M?.size ? M.size * C + ye : C, Ee = n((e) => {
87
+ Ce(e ?? void 0);
88
+ }, []);
89
+ r(() => {
90
+ ae?.(B);
91
+ }, [B, ae]), r(() => {
92
+ if (k) return k(I), () => {
93
+ I && k(void 0);
94
+ };
95
+ }, [I, k]), r(() => {
96
+ if (!A) return;
97
+ let e = () => {
98
+ A({
99
+ horizontalScrollPosition: W.data.horizontal,
100
+ verticalScrollPosition: W.data.vertical,
101
+ zoomLevel: U.data
102
+ });
103
+ }, t = U.subscribe(() => {
104
+ e();
105
+ }), n = W.subscribe(() => {
106
+ e();
107
+ });
108
+ return e(), () => {
109
+ t(), n();
110
+ };
111
+ }, [
112
+ A,
113
+ W,
114
+ U
115
+ ]), r(() => {
116
+ let e = U.data, t = () => {
117
+ B && e !== 1 && V(!1);
118
+ }, n = U.subscribe((n) => {
119
+ e = n, t();
120
+ });
121
+ return t(), () => {
122
+ n();
123
+ };
124
+ }, [B, U]), r(() => {
125
+ let e = H.subscribe((e) => {
126
+ W.next({
127
+ horizontal: isNaN(e.x) ? W.data.horizontal : e.x,
128
+ vertical: isNaN(e.y) ? W.data.vertical : e.y
129
+ });
130
+ });
131
+ return () => {
132
+ e();
133
+ };
134
+ }, [H, W]);
135
+ let De = n((e) => {
136
+ !j || !F.current || j.next({
137
+ origin: F.current,
138
+ position: e
139
+ });
140
+ }, [j]), Oe = m((e) => {
141
+ !j || !F.current || j.next({
142
+ origin: F.current,
143
+ position: e / z
144
+ });
145
+ }, T, {
146
+ leading: !0,
147
+ trailing: !0
148
+ }), X = n((t) => {
149
+ let { internalZoomLevel: n, positionX: r, positionY: i } = t;
150
+ if (n === 0) throw Error("internalZoomLevel cannot be 0");
151
+ let { newPositionX: a, newPositionY: o } = e.getSanitizedScrollPosition({
152
+ devicePixelRatio: z,
153
+ headerHeight: b,
154
+ internalZoomLevel: n,
155
+ isLinked: B,
156
+ positionX: r,
157
+ positionY: i,
158
+ treeCanvasHeight: K,
159
+ treeCanvasWidth: G,
160
+ treeHeight: Y,
161
+ treePadding: N
162
+ }), s = o !== H.data.y;
163
+ H.next({
164
+ x: a,
165
+ y: o
166
+ }), B && n === 1 && s && Oe(o);
167
+ }, [
168
+ H,
169
+ z,
170
+ b,
171
+ B,
172
+ K,
173
+ G,
174
+ Y,
175
+ N,
176
+ Oe
177
+ ]);
178
+ r(() => {
179
+ X({
180
+ internalZoomLevel: U.data,
181
+ positionX: H.data.x,
182
+ positionY: H.data.y
183
+ });
184
+ }, [
185
+ H,
186
+ X,
187
+ U
188
+ ]);
189
+ let Z = n((e) => {
190
+ let t = e ?? j?.data?.position ?? 0;
191
+ U.next(1), V(!0), X({
192
+ internalZoomLevel: 1,
193
+ positionX: 0,
194
+ positionY: t
195
+ }), e !== void 0 && De(t);
196
+ }, [
197
+ De,
198
+ j,
199
+ X,
200
+ U
201
+ ]), ke = n((e) => {
202
+ V(!1), U.next(e.zoomLevel), X({
203
+ internalZoomLevel: e.zoomLevel,
204
+ positionX: e.positionX,
205
+ positionY: e.positionY
206
+ });
207
+ }, [X, U]), Ae = n(() => {
208
+ if (!M?.size) {
209
+ Z(0);
210
+ return;
211
+ }
212
+ Z(e.getScrollPositionFromTreeVisibility({
213
+ itemHeight: C,
214
+ treeCanvasHeight: K,
215
+ treeHeight: Y,
216
+ treeSize: M.size,
217
+ verticalScrollPosition: W.data.vertical,
218
+ zoomLevel: U.data
219
+ }));
220
+ }, [
221
+ C,
222
+ Z,
223
+ W,
224
+ M,
225
+ K,
226
+ Y,
227
+ U
228
+ ]);
229
+ i(ce, () => ({
230
+ link: Z,
231
+ syncScrollToVisibleTree: Ae,
232
+ unlink: ke
233
+ }), [
234
+ Z,
235
+ Ae,
236
+ ke
237
+ ]);
238
+ let je = n((e, t) => {
239
+ H.next({
240
+ x: H.data.x / t * e,
241
+ y: H.data.y / t * e
242
+ }), we(e);
243
+ }, [H]);
244
+ f(c.getInstance(), { callback: je });
245
+ let Q = n((t) => e.getTickMarkScale({
246
+ geneticTreeWidth: M?.maxBranchLength,
247
+ maxScaleWidthPx: E,
248
+ minGeneticScaleUnit: e.getMinGeneticScaleUnit(M),
249
+ minScaleWidthPx: te,
250
+ scaleIncrements: de,
251
+ treeWidthMinusPadding: q,
252
+ zoomLevel: t
253
+ }), [
254
+ E,
255
+ te,
256
+ de,
257
+ M,
258
+ q
259
+ ]), $ = n((t, n) => e.getPathPropertiesFromCanvas({
260
+ canvas: t,
261
+ devicePixelRatio: z,
262
+ event: n,
263
+ treeAssembly: L
264
+ }), [z, L]);
265
+ r(() => {
266
+ if (!j) return;
267
+ let e = j.data, t = U.data, n = () => {
268
+ !e || e.origin === F.current || B && t === 1 && H.next({
269
+ x: H.data.x * z,
270
+ y: e.position * z
271
+ });
272
+ }, r = j.subscribe((t) => {
273
+ e = t, n();
274
+ }), i = U.subscribe((e) => {
275
+ t = e, n();
276
+ });
277
+ return () => {
278
+ r(), i();
279
+ };
280
+ }, [
281
+ H,
282
+ z,
283
+ j,
284
+ B,
285
+ U
286
+ ]), r(() => {
287
+ if (!M || !J) {
288
+ R(null);
289
+ return;
290
+ }
291
+ R(e.assembleTree({
292
+ ancestorDotRadius: h,
293
+ itemHeight: C,
294
+ leafDotRadius: w,
295
+ minimumDistancePercentageToShowLabel: ee,
296
+ pixelToGeneticDistanceRatio: J,
297
+ rootNode: M,
298
+ sortedLeafNames: me,
299
+ treeCanvasWidth: G,
300
+ treePadding: N
301
+ }));
302
+ }, [
303
+ h,
304
+ C,
305
+ w,
306
+ me,
307
+ ee,
308
+ J,
309
+ M,
310
+ G,
311
+ N
312
+ ]), r(() => {
313
+ if (!I || !L || !M) return;
314
+ let t, n = U.data, r = Q(n), i = x?.data?.highlightedNodeNames ?? [], a = j?.data?.position ?? 0, o = W.data.horizontal, s = W.data.vertical, c = P?.data, l = () => {
315
+ cancelAnimationFrame(t), t = requestAnimationFrame(() => {
316
+ e.drawTreeCanvas({
317
+ backgroundColor: _,
318
+ canvas: I,
319
+ devicePixelRatio: z,
320
+ dimFn: v,
321
+ fontFamily: y,
322
+ geneticTreeWidth: M.maxBranchLength,
323
+ headerHeight: b,
324
+ highlightedNodeNames: i,
325
+ horizontalScrollPosition: o,
326
+ isLinked: B,
327
+ itemHeight: C,
328
+ nodeNameColors: ie,
329
+ pixelToGeneticDistanceRatio: J,
330
+ range: c,
331
+ regularFillColorSupportLine: le,
332
+ scaleColor: ue,
333
+ scrollPosition: a,
334
+ shouldShowDistances: fe,
335
+ shouldShowSupportLinesWhenUnlinked: pe,
336
+ supportLineColorLinked: he,
337
+ supportLineColorUnlinked: ge,
338
+ tickerMarkScale: r,
339
+ treeAssembly: L,
340
+ treeCanvasHeight: K,
341
+ treeCanvasWidth: G,
342
+ treeColor: _e,
343
+ treeFont: ve,
344
+ treePadding: N,
345
+ verticalScrollPosition: s,
346
+ zoomLevel: n
347
+ });
348
+ });
349
+ }, u = x ? x.subscribe((e) => {
350
+ i = e.highlightedNodeNames, l();
351
+ }) : () => null, d = W.subscribe((e) => {
352
+ o = e.horizontal, s = e.vertical, l();
353
+ }), f = U.subscribe((e) => {
354
+ n = e, r = Q(e), l();
355
+ }), p = j?.subscribe((e) => {
356
+ e.origin !== F.current && (a = e.position, l());
357
+ }), m = P?.subscribe((e) => {
358
+ c = e, l();
359
+ });
360
+ return l(), () => {
361
+ u(), p?.(), d(), f(), m?.(), cancelAnimationFrame(t);
362
+ };
363
+ }, [
364
+ _,
365
+ z,
366
+ v,
367
+ x,
368
+ j,
369
+ P,
370
+ y,
371
+ Q,
372
+ b,
373
+ B,
374
+ C,
375
+ J,
376
+ le,
377
+ ue,
378
+ W,
379
+ fe,
380
+ pe,
381
+ ie,
382
+ he,
383
+ ge,
384
+ M,
385
+ L,
386
+ I,
387
+ K,
388
+ G,
389
+ _e,
390
+ ve,
391
+ N,
392
+ U
393
+ ]), r(() => {
394
+ if (!I) return;
395
+ let t = U.data, n = {
396
+ currentX: 0,
397
+ currentY: 0,
398
+ x: 0,
399
+ y: 0
400
+ }, r = !1, i = () => {
401
+ x?.data?.highlightedNodeNames?.length && x.next({ highlightedNodeNames: [] });
402
+ }, a = (e) => e.offsetY < b, o = (e) => {
403
+ if (a(e)) {
404
+ I.style.cursor = "default";
405
+ return;
406
+ }
407
+ n = {
408
+ currentX: H.data.x,
409
+ currentY: H.data.y,
410
+ x: e.clientX,
411
+ y: e.clientY
412
+ }, r = !0;
413
+ }, s = (e) => {
414
+ if (a(e)) {
415
+ r = !1, I.style.cursor = "default", i();
416
+ return;
417
+ }
418
+ if (r) {
419
+ I.style.cursor = "move";
420
+ let r = e.clientX - n.x, i = e.clientY - n.y, a = n.currentX - r, o = n.currentY - i, s = a;
421
+ t === 1 && Math.abs(r) < se && n.currentX === 0 && (s = 0), X({
422
+ internalZoomLevel: t,
423
+ positionX: s,
424
+ positionY: o
425
+ });
426
+ return;
427
+ }
428
+ let o = $(I, e);
429
+ o ? (I.style.cursor = "pointer", x?.next({ highlightedNodeNames: o.subTreeLeaveNames })) : (I.style.cursor = "default", i());
430
+ }, c = (e) => {
431
+ if (r = !1, a(e)) return;
432
+ let t = $(I, e);
433
+ t && oe?.({
434
+ mouseEvent: e,
435
+ pathProperties: t
436
+ });
437
+ }, l = (n) => {
438
+ if (n.preventDefault(), a(n)) return;
439
+ if (n.shiftKey) {
440
+ X({
441
+ internalZoomLevel: t,
442
+ positionX: H.data.x + (n.deltaX || n.deltaY),
443
+ positionY: H.data.y
444
+ });
445
+ return;
446
+ }
447
+ if (n.metaKey || n.ctrlKey) {
448
+ X({
449
+ internalZoomLevel: t,
450
+ positionX: H.data.x,
451
+ positionY: H.data.y + (n.deltaX || n.deltaY)
452
+ });
453
+ return;
454
+ }
455
+ let r = Math.min(O, Math.max(re, Y / K * .2)), i = Math.min(D, Math.max(ne, t + (n.deltaY > 0 ? r : -r))), o = n.offsetY - b, s = e.getNewScrollPositionForZoomLevel({
456
+ currentZoomLevel: t,
457
+ dimensionSize: Y,
458
+ eventOffset: o,
459
+ newZoomLevel: i,
460
+ scrollPosition: H.data.y
461
+ }), c = e.getNewScrollPositionForZoomLevel({
462
+ currentZoomLevel: t,
463
+ dimensionSize: G,
464
+ eventOffset: n.offsetX,
465
+ newZoomLevel: i,
466
+ scrollPosition: H.data.x
467
+ });
468
+ U.next(i), X(i === 1 ? {
469
+ internalZoomLevel: 1,
470
+ positionX: c,
471
+ positionY: j?.data?.position ?? 0
472
+ } : {
473
+ internalZoomLevel: i,
474
+ positionX: c,
475
+ positionY: s
476
+ });
477
+ }, u = () => {
478
+ r = !1, i();
479
+ }, d = U.subscribe((e) => {
480
+ t = e;
481
+ });
482
+ return I.addEventListener("mousemove", s), I.addEventListener("mousedown", o), I.addEventListener("mouseup", c), I.addEventListener("mouseout", u), I.addEventListener("wheel", l, { passive: !1 }), () => {
483
+ I.removeEventListener("mousemove", s), I.removeEventListener("mousedown", o), I.removeEventListener("mouseup", c), I.removeEventListener("mouseout", u), I.removeEventListener("wheel", l), d();
484
+ };
485
+ }, [
486
+ H,
487
+ x,
488
+ j,
489
+ $,
490
+ b,
491
+ D,
492
+ O,
493
+ ne,
494
+ re,
495
+ oe,
496
+ se,
497
+ I,
498
+ K,
499
+ G,
500
+ Y,
501
+ X,
502
+ U
503
+ ]);
504
+ let Me = !!M && G > 0 && M.size > 0;
505
+ return /* @__PURE__ */ p(t, {
506
+ ref: be,
507
+ sx: {
508
+ height: "100%",
509
+ overflow: "clip",
510
+ position: "relative",
511
+ width: "100%"
512
+ },
513
+ children: /* @__PURE__ */ p(t, {
514
+ ref: F,
515
+ sx: {
516
+ height: Te,
517
+ overflowY: "hidden",
518
+ position: "absolute",
519
+ width: G
520
+ },
521
+ children: Me && /* @__PURE__ */ p(t, {
522
+ "aria-label": g,
523
+ component: "canvas",
524
+ ref: Ee,
525
+ role: "figure",
526
+ sx: {
527
+ height: Te,
528
+ width: G
529
+ }
530
+ })
531
+ })
532
+ });
533
+ };
534
+ //#endregion
535
+ export { h as PhylogeneticTree };
536
+
537
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["r","n","t"],"sources":["../../../../../node_modules/.pnpm/use-debounce@10.1.1_react@19.2.7/node_modules/use-debounce/dist/index.module.js","../../../src/components/PhylogeneticTree/PhylogeneticTree.tsx"],"sourcesContent":["import{useRef as r,useMemo as n,useEffect as t,useState as e,useCallback as u}from\"react\";function c(e,u,c,i){var l=this,a=r(null),o=r(0),f=r(0),v=r(null),d=r([]),s=r(),m=r(),h=r(e),g=r(!0),x=r(),E=r();h.current=e;var b=\"undefined\"!=typeof window,p=!u&&0!==u&&b;if(\"function\"!=typeof e)throw new TypeError(\"Expected a function\");u=+u||0;var y=!!(c=c||{}).leading,w=!(\"trailing\"in c)||!!c.trailing,T=!!c.flushOnExit&&w,O=\"maxWait\"in c,F=\"debounceOnServer\"in c&&!!c.debounceOnServer,L=O?Math.max(+c.maxWait||0,u):null,A=n(function(){var r=function(r){var n=d.current,t=s.current;return d.current=s.current=null,o.current=r,f.current=f.current||r,m.current=h.current.apply(t,n)},n=function(r,n){p&&cancelAnimationFrame(v.current),v.current=p?requestAnimationFrame(r):setTimeout(r,n)},t=function(r){if(!g.current)return!1;var n=r-a.current;return!a.current||n>=u||n<0||O&&r-o.current>=L},e=function(n){return v.current=null,w&&d.current?r(n):(d.current=s.current=null,m.current)},c=function r(){var c=Date.now();if(y&&f.current===o.current&&A(),t(c))return e(c);if(g.current){var i=u-(c-a.current),l=O?Math.min(i,L-(c-o.current)):i;n(r,l)}},A=function(){i&&i({})},D=function(){if(b||F){var e,i=Date.now(),f=t(i);if(d.current=[].slice.call(arguments),s.current=l,a.current=i,T&&!x.current&&(x.current=function(){var r;\"hidden\"===(null==(r=globalThis.document)?void 0:r.visibilityState)&&E.current.flush()},null==(e=globalThis.document)||null==e.addEventListener||e.addEventListener(\"visibilitychange\",x.current)),f){if(!v.current&&g.current)return o.current=a.current,n(c,u),y?r(a.current):m.current;if(O)return n(c,u),r(a.current)}return v.current||n(c,u),m.current}};return D.cancel=function(){var r=v.current;r&&(p?cancelAnimationFrame(v.current):clearTimeout(v.current)),o.current=0,d.current=a.current=s.current=v.current=null,r&&i&&i({})},D.isPending=function(){return!!v.current},D.flush=function(){return v.current?e(Date.now()):m.current},D},[y,O,u,L,w,T,p,b,F,i]);return E.current=A,t(function(){return g.current=!0,function(){var r;T&&E.current.flush(),x.current&&(null==(r=globalThis.document)||null==r.removeEventListener||r.removeEventListener(\"visibilitychange\",x.current),x.current=null),g.current=!1}},[T]),A}function i(r,n){return r===n}function l(n,t,l){var a=l&&l.equalityFn||i,o=r(n),f=e({})[1],v=c(u(function(r){o.current=r,f({})},[f]),t,l,f),d=r(n);return a(d.current,n)||(v(n),d.current=n),[o.current,v]}function a(r,n,t){var e=void 0===t?{}:t,u=e.leading,i=e.trailing,l=e.flushOnExit;return c(r,n,{maxWait:n,leading:void 0===u||u,trailing:void 0===i||i,flushOnExit:void 0!==l&&l})}export{l as useDebounce,c as useDebouncedCallback,a as useThrottledCallback};\n//# sourceMappingURL=index.module.js.map\n","import { Box } from '@mui/material';\nimport type { Ref } from 'react';\nimport {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\nimport { DevicePixelRatioService } from '@gen-epix/ui-core/classes/services/DevicePixelRatioService';\nimport { Subject } from '@gen-epix/ui-core/classes/Subject';\nimport { useScrollbarSize } from '@gen-epix/ui-core/hooks/useScrollbarSize';\nimport { useDimensions } from '@gen-epix/ui-core/hooks/useDimensions';\nimport { useSubscribable } from '@gen-epix/ui-core/hooks/useSubscribable';\n\nimport type {\n TreeAssembly,\n TreeNode,\n TreePathProperties,\n} from '../../models/tree';\nimport { TreeUtil } from '../../utils/TreeUtil';\n\nexport type PhylogeneticTreeHighlightedNodeNamesSubjectValue = {\n highlightedNodeNames: string[];\n};\n\nexport type PhylogeneticTreePathClickEvent = {\n mouseEvent: MouseEvent;\n pathProperties: TreePathProperties;\n};\n\nexport type PhylogeneticTreeProps = {\n readonly ancestorDotRadius: number;\n readonly ariaLabel: string;\n readonly backgroundColor: string;\n readonly dimFn: (color: string) => string;\n readonly fontFamily: string;\n readonly headerHeight: number;\n readonly highlightedNodeNamesSubject?: Subject<PhylogeneticTreeHighlightedNodeNamesSubjectValue>;\n readonly initialViewState?: Partial<PhylogeneticTreeViewState>;\n readonly itemHeight: number;\n readonly leafDotRadius: number;\n readonly linkedScrollDebounceDelayMs: number;\n readonly maxScaleWidthPx: number;\n readonly maxZoomLevel: number;\n readonly maxZoomSpeed: number;\n readonly minimumDistancePercentageToShowLabel: number;\n readonly minScaleWidthPx: number;\n readonly minZoomLevel: number;\n readonly minZoomSpeed: number;\n readonly nodeNameColors?: { [key: string]: string } | null;\n readonly onCanvasChange?: (canvas?: HTMLCanvasElement) => void;\n readonly onLinkStateChange?: (isLinked: boolean) => void;\n readonly onPathClick?: (event: PhylogeneticTreePathClickEvent) => void;\n readonly onViewStateChange?: (viewState: PhylogeneticTreeViewState) => void;\n readonly panningThreshold: number;\n readonly ref?: Ref<PhylogeneticTreeRef>;\n readonly regularFillColorSupportLine: string;\n readonly scaleColor: string;\n readonly scaleIncrements: number[];\n readonly scrollSubject?: Subject<PhylogeneticTreeScrollSubjectValue>;\n readonly shouldShowDistances: boolean;\n readonly shouldShowSupportLinesWhenUnlinked: boolean;\n readonly sortedLeafNames: string[];\n readonly supportLineColorLinked: string;\n readonly supportLineColorUnlinked: string;\n readonly tree?: TreeNode;\n readonly treeColor: string;\n readonly treeFont: string;\n readonly treePadding: number;\n readonly visibleRangeSubject?: Subject<PhylogeneticTreeVisibleRangeSubjectValue>;\n};\n\nexport interface PhylogeneticTreeRef {\n link: (verticalPosition?: number) => void;\n syncScrollToVisibleTree: () => void;\n unlink: (viewState: { positionX: number; positionY: number; zoomLevel: number }) => void;\n}\n\nexport type PhylogeneticTreeScrollSubjectValue = {\n origin: HTMLElement;\n position: number;\n};\n\nexport type PhylogeneticTreeViewState = {\n horizontalScrollPosition: number;\n verticalScrollPosition: number;\n zoomLevel: number;\n};\n\nexport type PhylogeneticTreeVisibleRangeSubjectValue = {\n endIndex: number;\n startIndex: number;\n};\n\nexport const PhylogeneticTree = ({\n ancestorDotRadius,\n ariaLabel,\n backgroundColor,\n dimFn,\n fontFamily,\n headerHeight,\n highlightedNodeNamesSubject,\n initialViewState,\n itemHeight,\n leafDotRadius,\n linkedScrollDebounceDelayMs,\n maxScaleWidthPx,\n maxZoomLevel,\n maxZoomSpeed,\n minimumDistancePercentageToShowLabel,\n minScaleWidthPx,\n minZoomLevel,\n minZoomSpeed,\n nodeNameColors,\n onCanvasChange,\n onLinkStateChange,\n onPathClick,\n onViewStateChange,\n panningThreshold,\n ref,\n regularFillColorSupportLine,\n scaleColor,\n scaleIncrements,\n scrollSubject,\n shouldShowDistances,\n shouldShowSupportLinesWhenUnlinked,\n sortedLeafNames,\n supportLineColorLinked,\n supportLineColorUnlinked,\n tree,\n treeColor,\n treeFont,\n treePadding,\n visibleRangeSubject,\n}: PhylogeneticTreeProps) => {\n const scrollbarSize = useScrollbarSize();\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const { dimensions: { height, width } } = useDimensions(containerRef);\n const [treeCanvas, setTreeCanvas] = useState<HTMLCanvasElement>();\n const [treeAssembly, setTreeAssembly] = useState<TreeAssembly>(null);\n const [devicePixelRatio, setDevicePixelRatio] = useState<number>(DevicePixelRatioService.getInstance().data);\n const [isLinked, setIsLinked] = useState(true);\n const canvasScrollSubject = useMemo(() => new Subject<{ x: number; y: number }>({ x: 0, y: 0 }), []);\n const zoomLevelSubject = useMemo(() => new Subject<number>(!isNaN(initialViewState?.zoomLevel) ? initialViewState.zoomLevel : 1), [initialViewState]);\n const scrollPositionSubject = useMemo(() => new Subject<{ horizontal: number; vertical: number }>({\n horizontal: !isNaN(initialViewState?.horizontalScrollPosition) ? initialViewState.horizontalScrollPosition : 0,\n vertical: !isNaN(initialViewState?.verticalScrollPosition) ? initialViewState.verticalScrollPosition : 0,\n }), [initialViewState]);\n\n const treeCanvasWidth = width;\n const treeCanvasHeight = Math.max(0, height - headerHeight);\n const combinedCanvasHeight = Math.max(0, height);\n const treeWidthMinusPadding = treeCanvasWidth - (2 * treePadding);\n const pixelToGeneticDistanceRatio = tree?.maxBranchLength ? treeWidthMinusPadding / tree.maxBranchLength.toNumber() : null;\n const treeHeight = tree?.size ? (tree.size * itemHeight) + scrollbarSize : itemHeight;\n\n const handleTreeCanvasRef = useCallback((canvas: HTMLCanvasElement | null) => {\n setTreeCanvas(canvas ?? undefined);\n }, []);\n\n useEffect(() => {\n onLinkStateChange?.(isLinked);\n }, [isLinked, onLinkStateChange]);\n\n useEffect(() => {\n if (!onCanvasChange) {\n return;\n }\n onCanvasChange(treeCanvas);\n\n return () => {\n if (treeCanvas) {\n onCanvasChange(undefined);\n }\n };\n }, [treeCanvas, onCanvasChange]);\n\n useEffect(() => {\n if (!onViewStateChange) {\n return;\n }\n\n const emitViewState = () => {\n onViewStateChange({\n horizontalScrollPosition: scrollPositionSubject.data.horizontal,\n verticalScrollPosition: scrollPositionSubject.data.vertical,\n zoomLevel: zoomLevelSubject.data,\n });\n };\n\n const unsubscribeFromZoomLevelSubject = zoomLevelSubject.subscribe(() => {\n emitViewState();\n });\n const unsubscribeFromScrollPositionSubject = scrollPositionSubject.subscribe(() => {\n emitViewState();\n });\n\n emitViewState();\n\n return () => {\n unsubscribeFromZoomLevelSubject();\n unsubscribeFromScrollPositionSubject();\n };\n }, [onViewStateChange, scrollPositionSubject, zoomLevelSubject]);\n\n useEffect(() => {\n let zoomLevel = zoomLevelSubject.data;\n\n const updateIsLinked = () => {\n if (isLinked && zoomLevel !== 1) {\n setIsLinked(false);\n }\n };\n\n const unsubscribeFromZoomLevelSubject = zoomLevelSubject.subscribe((data) => {\n zoomLevel = data;\n updateIsLinked();\n });\n updateIsLinked();\n\n return () => {\n unsubscribeFromZoomLevelSubject();\n };\n }, [isLinked, zoomLevelSubject]);\n\n useEffect(() => {\n const unsubscribe = canvasScrollSubject.subscribe((data) => {\n scrollPositionSubject.next({\n horizontal: !isNaN(data.x) ? data.x : scrollPositionSubject.data.horizontal,\n vertical: !isNaN(data.y) ? data.y : scrollPositionSubject.data.vertical,\n });\n });\n\n return () => {\n unsubscribe();\n };\n }, [canvasScrollSubject, scrollPositionSubject]);\n\n const emitScrollPosition = useCallback((position: number) => {\n if (!scrollSubject || !scrollContainerRef.current) {\n return;\n }\n\n scrollSubject.next({\n origin: scrollContainerRef.current,\n position,\n });\n }, [scrollSubject]);\n\n const updateScrollSubjectDebounced = useDebouncedCallback((position: number) => {\n if (!scrollSubject || !scrollContainerRef.current) {\n return;\n }\n\n scrollSubject.next({\n origin: scrollContainerRef.current,\n position: position / devicePixelRatio,\n });\n }, linkedScrollDebounceDelayMs, { leading: true, trailing: true });\n\n const updateScrollPosition = useCallback((params: { internalZoomLevel: number; positionX: number; positionY: number }) => {\n const { internalZoomLevel, positionX, positionY } = params;\n if (internalZoomLevel === 0) {\n throw new Error('internalZoomLevel cannot be 0');\n }\n\n const { newPositionX, newPositionY } = TreeUtil.getSanitizedScrollPosition({\n devicePixelRatio,\n headerHeight,\n internalZoomLevel,\n isLinked,\n positionX,\n positionY,\n treeCanvasHeight,\n treeCanvasWidth,\n treeHeight,\n treePadding,\n });\n\n const positionYChanged = newPositionY !== canvasScrollSubject.data.y;\n\n canvasScrollSubject.next({\n x: newPositionX,\n y: newPositionY,\n });\n\n if (isLinked && internalZoomLevel === 1 && positionYChanged) {\n updateScrollSubjectDebounced(newPositionY);\n }\n }, [canvasScrollSubject, devicePixelRatio, headerHeight, isLinked, treeCanvasHeight, treeCanvasWidth, treeHeight, treePadding, updateScrollSubjectDebounced]);\n\n useEffect(() => {\n updateScrollPosition({\n internalZoomLevel: zoomLevelSubject.data,\n positionX: canvasScrollSubject.data.x,\n positionY: canvasScrollSubject.data.y,\n });\n }, [canvasScrollSubject, updateScrollPosition, zoomLevelSubject]);\n\n const link = useCallback((verticalPosition?: number) => {\n const nextVerticalPosition = verticalPosition ?? scrollSubject?.data?.position ?? 0;\n\n zoomLevelSubject.next(1);\n setIsLinked(true);\n updateScrollPosition({\n internalZoomLevel: 1,\n positionX: 0,\n positionY: nextVerticalPosition,\n });\n\n if (verticalPosition !== undefined) {\n emitScrollPosition(nextVerticalPosition);\n }\n }, [emitScrollPosition, scrollSubject, updateScrollPosition, zoomLevelSubject]);\n\n const unlink = useCallback((viewState: { positionX: number; positionY: number; zoomLevel: number }) => {\n setIsLinked(false);\n zoomLevelSubject.next(viewState.zoomLevel);\n updateScrollPosition({\n internalZoomLevel: viewState.zoomLevel,\n positionX: viewState.positionX,\n positionY: viewState.positionY,\n });\n }, [updateScrollPosition, zoomLevelSubject]);\n\n const syncScrollToVisibleTree = useCallback(() => {\n if (!tree?.size) {\n link(0);\n return;\n }\n\n const newScrollPosition = TreeUtil.getScrollPositionFromTreeVisibility({\n itemHeight,\n treeCanvasHeight,\n treeHeight,\n treeSize: tree.size,\n verticalScrollPosition: scrollPositionSubject.data.vertical,\n zoomLevel: zoomLevelSubject.data,\n });\n\n link(newScrollPosition);\n }, [itemHeight, link, scrollPositionSubject, tree, treeCanvasHeight, treeHeight, zoomLevelSubject]);\n\n useImperativeHandle(ref, () => ({\n link,\n syncScrollToVisibleTree,\n unlink,\n }), [link, syncScrollToVisibleTree, unlink]);\n\n const devicePixelRatioServiceCallback = useCallback((newDevicePixelRatio: number, previousDevicePixelRatio: number) => {\n canvasScrollSubject.next({\n x: (canvasScrollSubject.data.x / previousDevicePixelRatio) * newDevicePixelRatio,\n y: (canvasScrollSubject.data.y / previousDevicePixelRatio) * newDevicePixelRatio,\n });\n setDevicePixelRatio(newDevicePixelRatio);\n }, [canvasScrollSubject]);\n\n useSubscribable(DevicePixelRatioService.getInstance(), {\n callback: devicePixelRatioServiceCallback,\n });\n\n const getTickerMarkScale = useCallback((zoomLevel: number) => {\n return TreeUtil.getTickMarkScale({\n geneticTreeWidth: tree?.maxBranchLength,\n maxScaleWidthPx,\n minGeneticScaleUnit: TreeUtil.getMinGeneticScaleUnit(tree),\n minScaleWidthPx,\n scaleIncrements,\n treeWidthMinusPadding,\n zoomLevel,\n });\n }, [maxScaleWidthPx, minScaleWidthPx, scaleIncrements, tree, treeWidthMinusPadding]);\n\n const getPathPropertiesFromCanvas = useCallback((canvas: HTMLCanvasElement, event: MouseEvent): TreePathProperties => {\n return TreeUtil.getPathPropertiesFromCanvas({\n canvas,\n devicePixelRatio,\n event,\n treeAssembly,\n });\n }, [devicePixelRatio, treeAssembly]);\n\n useEffect(() => {\n if (!scrollSubject) {\n return;\n }\n\n let scrollData = scrollSubject.data;\n let zoomLevel = zoomLevelSubject.data;\n\n const update = () => {\n if (!scrollData || scrollData.origin === scrollContainerRef.current) {\n return;\n }\n if (isLinked && zoomLevel === 1) {\n canvasScrollSubject.next({\n x: canvasScrollSubject.data.x * devicePixelRatio,\n y: scrollData.position * devicePixelRatio,\n });\n }\n };\n\n const unsubscribeFromScrollSubject = scrollSubject.subscribe((data) => {\n scrollData = data;\n update();\n });\n\n const unsubscribeFromZoomLevelSubject = zoomLevelSubject.subscribe((data) => {\n zoomLevel = data;\n update();\n });\n\n return () => {\n unsubscribeFromScrollSubject();\n unsubscribeFromZoomLevelSubject();\n };\n }, [canvasScrollSubject, devicePixelRatio, scrollSubject, isLinked, zoomLevelSubject]);\n\n useEffect(() => {\n if (!tree || !pixelToGeneticDistanceRatio) {\n setTreeAssembly(null);\n return;\n }\n\n setTreeAssembly(TreeUtil.assembleTree({\n ancestorDotRadius,\n itemHeight,\n leafDotRadius,\n minimumDistancePercentageToShowLabel,\n pixelToGeneticDistanceRatio,\n rootNode: tree,\n sortedLeafNames,\n treeCanvasWidth,\n treePadding,\n }));\n }, [ancestorDotRadius, itemHeight, leafDotRadius, sortedLeafNames, minimumDistancePercentageToShowLabel, pixelToGeneticDistanceRatio, tree, treeCanvasWidth, treePadding]);\n\n useEffect(() => {\n if (!treeCanvas || !treeAssembly || !tree) {\n return;\n }\n\n let animationFrameId: number;\n let zoomLevel: number = zoomLevelSubject.data;\n let tickerMarkScale = getTickerMarkScale(zoomLevel);\n let highlightedNodeNames: string[] = highlightedNodeNamesSubject?.data?.highlightedNodeNames ?? [];\n let scrollPosition = scrollSubject?.data?.position ?? 0;\n let horizontalScrollPosition = scrollPositionSubject.data.horizontal;\n let verticalScrollPosition = scrollPositionSubject.data.vertical;\n let range = visibleRangeSubject?.data;\n\n const render = () => {\n cancelAnimationFrame(animationFrameId);\n animationFrameId = requestAnimationFrame(() => {\n TreeUtil.drawTreeCanvas({\n backgroundColor,\n canvas: treeCanvas,\n devicePixelRatio,\n dimFn,\n fontFamily,\n geneticTreeWidth: tree.maxBranchLength,\n headerHeight,\n highlightedNodeNames,\n horizontalScrollPosition,\n isLinked,\n itemHeight,\n nodeNameColors,\n pixelToGeneticDistanceRatio,\n range,\n regularFillColorSupportLine,\n scaleColor,\n scrollPosition,\n shouldShowDistances,\n shouldShowSupportLinesWhenUnlinked,\n supportLineColorLinked,\n supportLineColorUnlinked,\n tickerMarkScale,\n treeAssembly,\n treeCanvasHeight,\n treeCanvasWidth,\n treeColor,\n treeFont,\n treePadding,\n verticalScrollPosition,\n zoomLevel,\n });\n });\n };\n\n const unsubscribeFromHighlighting = highlightedNodeNamesSubject ? highlightedNodeNamesSubject.subscribe((data) => {\n highlightedNodeNames = data.highlightedNodeNames;\n render();\n }) : (): null => null;\n\n const unsubscribeFromScrollPositionSubject = scrollPositionSubject.subscribe((data) => {\n horizontalScrollPosition = data.horizontal;\n verticalScrollPosition = data.vertical;\n render();\n });\n\n const unsubscribeFromZoomLevelSubject = zoomLevelSubject.subscribe((data) => {\n zoomLevel = data;\n tickerMarkScale = getTickerMarkScale(data);\n render();\n });\n\n const unsubscribeFromScrollSubject = scrollSubject?.subscribe((data) => {\n if (data.origin === scrollContainerRef.current) {\n return;\n }\n scrollPosition = data.position;\n render();\n });\n\n const unsubscribeFromVisibleRangeSubject = visibleRangeSubject?.subscribe((data) => {\n range = data;\n render();\n });\n\n render();\n\n return () => {\n unsubscribeFromHighlighting();\n unsubscribeFromScrollSubject?.();\n unsubscribeFromScrollPositionSubject();\n unsubscribeFromZoomLevelSubject();\n unsubscribeFromVisibleRangeSubject?.();\n cancelAnimationFrame(animationFrameId);\n };\n }, [\n backgroundColor,\n devicePixelRatio,\n dimFn,\n highlightedNodeNamesSubject,\n scrollSubject,\n visibleRangeSubject,\n fontFamily,\n getTickerMarkScale,\n headerHeight,\n isLinked,\n itemHeight,\n pixelToGeneticDistanceRatio,\n regularFillColorSupportLine,\n scaleColor,\n scrollPositionSubject,\n shouldShowDistances,\n shouldShowSupportLinesWhenUnlinked,\n nodeNameColors,\n supportLineColorLinked,\n supportLineColorUnlinked,\n tree,\n treeAssembly,\n treeCanvas,\n treeCanvasHeight,\n treeCanvasWidth,\n treeColor,\n treeFont,\n treePadding,\n zoomLevelSubject,\n ]);\n\n useEffect(() => {\n if (!treeCanvas) {\n return;\n }\n\n let zoomLevel = zoomLevelSubject.data;\n\n let pos = {\n currentX: 0,\n currentY: 0,\n x: 0,\n y: 0,\n };\n let followMouse = false;\n\n const clearHighlighting = () => {\n if (highlightedNodeNamesSubject?.data?.highlightedNodeNames?.length) {\n highlightedNodeNamesSubject.next({\n highlightedNodeNames: [],\n });\n }\n };\n\n const isEventInHeader = (event: MouseEvent | WheelEvent) => event.offsetY < headerHeight;\n\n const onMouseDown = (event: MouseEvent) => {\n if (isEventInHeader(event)) {\n treeCanvas.style.cursor = 'default';\n return;\n }\n\n pos = {\n currentX: canvasScrollSubject.data.x,\n currentY: canvasScrollSubject.data.y,\n x: event.clientX,\n y: event.clientY,\n };\n followMouse = true;\n };\n\n const onMouseMove = (event: MouseEvent) => {\n if (isEventInHeader(event)) {\n followMouse = false;\n treeCanvas.style.cursor = 'default';\n clearHighlighting();\n return;\n }\n\n if (followMouse) {\n treeCanvas.style.cursor = 'move';\n\n const deltaX = event.clientX - pos.x;\n const deltaY = event.clientY - pos.y;\n const scrollPositionX = pos.currentX - deltaX;\n const scrollPositionY = pos.currentY - deltaY;\n\n let sanitizedScrollPositionX = scrollPositionX;\n if (zoomLevel === 1 && Math.abs(deltaX) < panningThreshold && pos.currentX === 0) {\n sanitizedScrollPositionX = 0;\n }\n updateScrollPosition({ internalZoomLevel: zoomLevel, positionX: sanitizedScrollPositionX, positionY: scrollPositionY });\n return;\n }\n\n const pathProperties = getPathPropertiesFromCanvas(treeCanvas, event);\n if (pathProperties) {\n treeCanvas.style.cursor = 'pointer';\n highlightedNodeNamesSubject?.next({\n highlightedNodeNames: pathProperties.subTreeLeaveNames,\n });\n } else {\n treeCanvas.style.cursor = 'default';\n clearHighlighting();\n }\n };\n\n const onMouseUp = (event: MouseEvent) => {\n followMouse = false;\n\n if (isEventInHeader(event)) {\n return;\n }\n\n const pathProperties = getPathPropertiesFromCanvas(treeCanvas, event);\n if (pathProperties) {\n onPathClick?.({\n mouseEvent: event,\n pathProperties,\n });\n }\n };\n\n const onMouseWheel = (event: WheelEvent) => {\n event.preventDefault();\n\n if (isEventInHeader(event)) {\n return;\n }\n\n if (event.shiftKey) {\n updateScrollPosition({ internalZoomLevel: zoomLevel, positionX: canvasScrollSubject.data.x + (event.deltaX || event.deltaY), positionY: canvasScrollSubject.data.y });\n return;\n }\n if (event.metaKey || event.ctrlKey) {\n updateScrollPosition({ internalZoomLevel: zoomLevel, positionX: canvasScrollSubject.data.x, positionY: canvasScrollSubject.data.y + (event.deltaX || event.deltaY) });\n return;\n }\n\n const zoomSpeed = Math.min(maxZoomSpeed, Math.max(minZoomSpeed, treeHeight / treeCanvasHeight * 0.2));\n const newZoomLevel = Math.min(maxZoomLevel, Math.max(minZoomLevel, zoomLevel + (event.deltaY > 0 ? zoomSpeed : -zoomSpeed)));\n const treeBodyOffsetY = event.offsetY - headerHeight;\n\n const newScrollPositionY = TreeUtil.getNewScrollPositionForZoomLevel({\n currentZoomLevel: zoomLevel,\n dimensionSize: treeHeight,\n eventOffset: treeBodyOffsetY,\n newZoomLevel,\n scrollPosition: canvasScrollSubject.data.y,\n });\n const newScrollPositionX = TreeUtil.getNewScrollPositionForZoomLevel({\n currentZoomLevel: zoomLevel,\n dimensionSize: treeCanvasWidth,\n eventOffset: event.offsetX,\n newZoomLevel,\n scrollPosition: canvasScrollSubject.data.x,\n });\n zoomLevelSubject.next(newZoomLevel);\n if (newZoomLevel !== 1) {\n updateScrollPosition({ internalZoomLevel: newZoomLevel, positionX: newScrollPositionX, positionY: newScrollPositionY });\n } else {\n updateScrollPosition({ internalZoomLevel: 1, positionX: newScrollPositionX, positionY: scrollSubject?.data?.position ?? 0 });\n }\n };\n\n const onMouseOut = () => {\n followMouse = false;\n clearHighlighting();\n };\n\n const unsubscribeFromZoomLevelSubject = zoomLevelSubject.subscribe((data) => {\n zoomLevel = data;\n });\n\n treeCanvas.addEventListener('mousemove', onMouseMove);\n treeCanvas.addEventListener('mousedown', onMouseDown);\n treeCanvas.addEventListener('mouseup', onMouseUp);\n treeCanvas.addEventListener('mouseout', onMouseOut);\n treeCanvas.addEventListener('wheel', onMouseWheel, { passive: false });\n\n return () => {\n treeCanvas.removeEventListener('mousemove', onMouseMove);\n treeCanvas.removeEventListener('mousedown', onMouseDown);\n treeCanvas.removeEventListener('mouseup', onMouseUp);\n treeCanvas.removeEventListener('mouseout', onMouseOut);\n treeCanvas.removeEventListener('wheel', onMouseWheel);\n unsubscribeFromZoomLevelSubject();\n };\n }, [\n canvasScrollSubject,\n highlightedNodeNamesSubject,\n scrollSubject,\n getPathPropertiesFromCanvas,\n headerHeight,\n maxZoomLevel,\n maxZoomSpeed,\n minZoomLevel,\n minZoomSpeed,\n onPathClick,\n panningThreshold,\n treeCanvas,\n treeCanvasHeight,\n treeCanvasWidth,\n treeHeight,\n updateScrollPosition,\n zoomLevelSubject,\n ]);\n\n const shouldRenderCanvas = !!tree && treeCanvasWidth > 0 && tree.size > 0;\n\n return (\n <Box\n ref={containerRef}\n sx={{\n height: '100%',\n overflow: 'clip',\n position: 'relative',\n width: '100%',\n }}\n >\n <Box\n ref={scrollContainerRef}\n sx={{\n height: combinedCanvasHeight,\n overflowY: 'hidden',\n position: 'absolute',\n width: treeCanvasWidth,\n }}\n >\n {shouldRenderCanvas && (\n <Box\n aria-label={ariaLabel}\n component={'canvas'}\n ref={handleTreeCanvasRef}\n role={'figure'}\n sx={{\n height: combinedCanvasHeight,\n width: treeCanvasWidth,\n }}\n />\n )}\n </Box>\n </Box>\n );\n};\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { Decimal } from 'decimal.js';
2
+ export type TreeAssembly = {
3
+ ancestorNodes: Array<{
4
+ nodeNames: string[];
5
+ shape: Path2D;
6
+ }>;
7
+ distanceTexts: Array<{
8
+ nodeNames: string[];
9
+ text: string;
10
+ x: number;
11
+ y: number;
12
+ }>;
13
+ horizontalAncestorTreeLines: Array<{
14
+ nodeNames: string[];
15
+ shape: Path2D;
16
+ }>;
17
+ horizontalLinePathPropertiesMap: TreeAssemblyPathPropertiesMap;
18
+ leafNodes: Array<{
19
+ nodeName: string;
20
+ shape: Path2D;
21
+ }>;
22
+ leafTreeLines: Array<{
23
+ nodeName: string;
24
+ shape: Path2D;
25
+ }>;
26
+ nodePathPropertiesMap: TreeAssemblyPathPropertiesMap;
27
+ supportLines: Array<{
28
+ fromX: number;
29
+ fromY: number;
30
+ nodeName: string;
31
+ toX: number;
32
+ toY: number;
33
+ }>;
34
+ verticalAncestorTreeLines: Array<{
35
+ nodeNames: string[];
36
+ shape: Path2D;
37
+ }>;
38
+ verticalLinePathPropertiesMap: TreeAssemblyPathPropertiesMap;
39
+ };
40
+ export type TreeNode = {
41
+ address?: string;
42
+ branchLength?: Decimal;
43
+ children?: TreeNode[];
44
+ maxBranchLength?: Decimal;
45
+ name?: string;
46
+ size?: number;
47
+ subTreeLeaveNames?: string[];
48
+ subTreeNames?: string[];
49
+ };
50
+ export type TreePathProperties = {
51
+ subTreeLeaveNames: string[];
52
+ treeNode?: TreeNode;
53
+ };
54
+ type TreeAssemblyPathPropertiesMap = Map<Path2D, TreePathProperties>;
55
+ export {};
File without changes
@@ -0,0 +1,5 @@
1
+ import { TreeNode } from '../../models/tree';
2
+ export declare class NewickUtil {
3
+ static getSortedNames(node: TreeNode): string[];
4
+ static parse(newick: string): TreeNode;
5
+ }
@@ -0,0 +1 @@
1
+ export * from './NewickUtil';