@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.
- package/LICENSE +287 -0
- package/README.md +51 -0
- package/dist/_chunks/identity.js +820 -0
- package/dist/_chunks/identity.js.map +1 -0
- package/dist/components/PhylogeneticTree/PhylogeneticTree.d.ts +76 -0
- package/dist/components/PhylogeneticTree/index.d.ts +1 -0
- package/dist/components/PhylogeneticTree/index.js +537 -0
- package/dist/components/PhylogeneticTree/index.js.map +1 -0
- package/dist/models/tree.d.ts +55 -0
- package/dist/models/tree.js +0 -0
- package/dist/utils/NewickUtil/NewickUtil.d.ts +5 -0
- package/dist/utils/NewickUtil/index.d.ts +1 -0
- package/dist/utils/NewickUtil/index.js +50 -0
- package/dist/utils/NewickUtil/index.js.map +1 -0
- package/dist/utils/TreeUtil/TreeUtil.d.ts +496 -0
- package/dist/utils/TreeUtil/index.d.ts +1 -0
- package/dist/utils/TreeUtil/index.js +986 -0
- package/dist/utils/TreeUtil/index.js.map +1 -0
- package/package.json +82 -0
|
@@ -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 @@
|
|
|
1
|
+
export * from './NewickUtil';
|