react-msaview 5.1.1 → 5.2.1
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/README.md +41 -8
- package/bundle/index.js +17 -17
- package/bundle/index.js.LICENSE.txt +1 -1
- package/bundle/index.js.map +1 -1
- package/dist/calculateBlocks.d.ts +4 -10
- package/dist/calculateBlocks.js +12 -20
- package/dist/calculateBlocks.js.map +1 -1
- package/dist/components/ConservationTrack.js +20 -37
- package/dist/components/ConservationTrack.js.map +1 -1
- package/dist/components/MSAView.js +8 -1
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +3 -0
- package/dist/components/ResizeHandles.js +60 -105
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/TextTrack.js +25 -34
- package/dist/components/TextTrack.js.map +1 -1
- package/dist/components/Track.js +1 -1
- package/dist/components/Track.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +2 -2
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +20 -20
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.js +6 -1
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.js +1 -2
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -1
- package/dist/components/header/ColorSchemeMenu.js +1 -1
- package/dist/components/header/ColorSchemeMenu.js.map +1 -1
- package/dist/components/header/FileMenu.js +3 -2
- package/dist/components/header/FileMenu.js.map +1 -1
- package/dist/components/header/Header.js +1 -1
- package/dist/components/header/HeaderInfoArea.js +28 -8
- package/dist/components/header/HeaderInfoArea.js.map +1 -1
- package/dist/components/header/MSASettingsMenu.js +1 -1
- package/dist/components/header/MSASettingsMenu.js.map +1 -1
- package/dist/components/header/TreeSettingsMenu.js +1 -1
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/ZoomControls.js +7 -2
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/ZoomMenu.js +9 -0
- package/dist/components/header/ZoomMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +24 -8
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/minimap/Minimap.js +6 -17
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.js +7 -17
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/minimap/minimapLayout.d.ts +9 -0
- package/dist/components/minimap/minimapLayout.js +15 -0
- package/dist/components/minimap/minimapLayout.js.map +1 -0
- package/dist/components/msa/MSACanvas.js +6 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +5 -1
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/getVisibleLeaves.d.ts +6 -0
- package/dist/components/msa/getVisibleLeaves.js +9 -0
- package/dist/components/msa/getVisibleLeaves.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +2 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +5 -6
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +2 -1
- package/dist/components/msa/renderMSABlock.js +100 -88
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +5 -4
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/msa/visibleColRange.d.ts +8 -0
- package/dist/components/msa/visibleColRange.js +10 -0
- package/dist/components/msa/visibleColRange.js.map +1 -0
- package/dist/components/renderCtx.d.ts +7 -0
- package/dist/components/renderCtx.js +2 -0
- package/dist/components/renderCtx.js.map +1 -0
- package/dist/components/tracks/renderTracksSvg.d.ts +6 -5
- package/dist/components/tracks/renderTracksSvg.js +13 -5
- package/dist/components/tracks/renderTracksSvg.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -10
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +5 -4
- package/dist/components/tree/renderTreeCanvas.js +18 -26
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/util.d.ts +0 -14
- package/dist/components/util.js +0 -58
- package/dist/components/util.js.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -1
- package/dist/flatToTree.js +6 -0
- package/dist/flatToTree.js.map +1 -1
- package/dist/hierarchy.d.ts +3 -1
- package/dist/hierarchy.js +142 -89
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/launchInterProScan.js +22 -9
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/measureTextCanvas.js +2 -1
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model.d.ts +234 -176
- package/dist/model.js +285 -259
- package/dist/model.js.map +1 -1
- package/dist/parseAsn1.js +8 -2
- package/dist/parseAsn1.js.map +1 -1
- package/dist/renderToSvg.d.ts +1 -1
- package/dist/renderToSvg.js +43 -46
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +0 -9
- package/dist/rowCoordinateCalculations.js +0 -20
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/setFontSize.d.ts +3 -0
- package/dist/setFontSize.js +14 -0
- package/dist/setFontSize.js.map +1 -0
- package/dist/useDevicePixelRatio.d.ts +1 -0
- package/dist/useDevicePixelRatio.js +27 -0
- package/dist/useDevicePixelRatio.js.map +1 -0
- package/dist/useWheelScroll.d.ts +3 -1
- package/dist/useWheelScroll.js +64 -22
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/util.d.ts +5 -0
- package/dist/util.js +59 -1
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webpack.js +0 -1
- package/dist/webpack.js.map +1 -1
- package/dist/wheelZoom.d.ts +4 -0
- package/dist/wheelZoom.js +43 -0
- package/dist/wheelZoom.js.map +1 -0
- package/package.json +5 -5
- package/src/calculateBlocks.ts +18 -51
- package/src/components/ConservationTrack.tsx +20 -45
- package/src/components/MSAView.tsx +10 -1
- package/src/components/ResizeHandles.tsx +101 -113
- package/src/components/TextTrack.tsx +31 -38
- package/src/components/Track.tsx +1 -1
- package/src/components/VerticalScrollbar.tsx +2 -2
- package/src/components/dialogs/ExportSVGDialog.tsx +27 -17
- package/src/components/dialogs/InterProScanDialog.tsx +6 -1
- package/src/components/dialogs/UserProvidedDomainsDialog.tsx +1 -2
- package/src/components/header/ColorSchemeMenu.tsx +1 -0
- package/src/components/header/FileMenu.tsx +3 -1
- package/src/components/header/Header.tsx +1 -1
- package/src/components/header/HeaderInfoArea.tsx +32 -7
- package/src/components/header/MSASettingsMenu.tsx +1 -0
- package/src/components/header/TreeSettingsMenu.tsx +1 -0
- package/src/components/header/ZoomControls.tsx +14 -1
- package/src/components/header/ZoomMenu.tsx +10 -0
- package/src/components/header/settingsMenuItems.ts +24 -8
- package/src/components/minimap/Minimap.tsx +6 -20
- package/src/components/minimap/MinimapSVG.tsx +10 -27
- package/src/components/minimap/minimapLayout.ts +17 -0
- package/src/components/msa/MSACanvas.tsx +9 -0
- package/src/components/msa/MSACanvasBlock.tsx +7 -1
- package/src/components/msa/MSAMouseoverCanvas.tsx +4 -3
- package/src/components/msa/getVisibleLeaves.ts +21 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +9 -9
- package/src/components/msa/renderMSABlock.ts +123 -125
- package/src/components/msa/renderMSAMouseover.ts +5 -4
- package/src/components/msa/visibleColRange.ts +17 -0
- package/src/components/renderCtx.ts +29 -0
- package/src/components/tracks/renderTracksSvg.ts +20 -10
- package/src/components/tree/TreeCanvas.tsx +3 -1
- package/src/components/tree/TreeCanvasBlock.tsx +2 -12
- package/src/components/tree/renderTreeCanvas.ts +27 -30
- package/src/components/util.ts +0 -81
- package/src/constants.ts +8 -0
- package/src/flatToTree.test.ts +30 -0
- package/src/flatToTree.ts +10 -1
- package/src/hierarchy.test.ts +53 -1
- package/src/hierarchy.ts +153 -100
- package/src/index.ts +8 -0
- package/src/launchInterProScan.ts +33 -11
- package/src/measureTextCanvas.ts +3 -1
- package/src/model.ts +359 -306
- package/src/parseAsn1.test.ts +6 -0
- package/src/parseAsn1.ts +11 -3
- package/src/renderToSvg.tsx +99 -95
- package/src/rowCoordinateCalculations.test.ts +0 -51
- package/src/rowCoordinateCalculations.ts +0 -23
- package/src/setFontSize.test.ts +33 -0
- package/src/setFontSize.ts +20 -0
- package/src/useDevicePixelRatio.ts +29 -0
- package/src/useWheelScroll.ts +79 -21
- package/src/util.ts +60 -1
- package/src/version.ts +1 -1
- package/src/webpack.ts +0 -1
- package/src/wheelZoom.test.ts +46 -0
- package/src/wheelZoom.ts +47 -0
package/src/hierarchy.ts
CHANGED
|
@@ -19,45 +19,72 @@ export interface HierarchyLink<T = NodeWithIds> {
|
|
|
19
19
|
target: HierarchyNode<T>
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
// All traversals below are iterative (explicit stack / reversed-preorder) rather
|
|
23
|
+
// than recursive: phylogenetic trees can be deeply unbalanced (a caterpillar tree
|
|
24
|
+
// has depth ~= leaf count), which overflows the JS call stack on recursion.
|
|
25
|
+
|
|
26
|
+
// Pre-order: every parent precedes all of its descendants. Iterating the result
|
|
27
|
+
// in reverse therefore yields a valid post-order (children before parents), which
|
|
28
|
+
// the accumulation helpers rely on.
|
|
29
|
+
export function descendants<T>(node: HierarchyNode<T>): HierarchyNode<T>[] {
|
|
30
|
+
const result: HierarchyNode<T>[] = []
|
|
31
|
+
const stack = [node]
|
|
32
|
+
while (stack.length > 0) {
|
|
33
|
+
const n = stack.pop()!
|
|
34
|
+
result.push(n)
|
|
35
|
+
if (n.children) {
|
|
36
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
37
|
+
stack.push(n.children[i]!)
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
|
-
|
|
33
|
-
return h
|
|
41
|
+
return result
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
function
|
|
44
|
+
function computeHeight<T>(node: HierarchyNode<T>) {
|
|
45
|
+
const nodes = descendants(node)
|
|
46
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
47
|
+
const n = nodes[i]!
|
|
48
|
+
let h = 0
|
|
49
|
+
if (n.children) {
|
|
50
|
+
for (const child of n.children) {
|
|
51
|
+
if (child.height + 1 > h) {
|
|
52
|
+
h = child.height + 1
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
n.height = h
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function hierarchy<T>(
|
|
37
61
|
data: T,
|
|
38
62
|
childrenAccessor: (d: T) => T[] | undefined,
|
|
39
|
-
parent: HierarchyNode<T> | null,
|
|
40
|
-
depth: number,
|
|
41
63
|
): HierarchyNode<T> {
|
|
42
|
-
const
|
|
43
|
-
const node: HierarchyNode<T> = {
|
|
64
|
+
const root: HierarchyNode<T> = {
|
|
44
65
|
data,
|
|
45
66
|
children: null,
|
|
46
|
-
parent,
|
|
47
|
-
depth,
|
|
67
|
+
parent: null,
|
|
68
|
+
depth: 0,
|
|
48
69
|
height: 0,
|
|
49
70
|
}
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
const stack = [root]
|
|
72
|
+
while (stack.length > 0) {
|
|
73
|
+
const node = stack.pop()!
|
|
74
|
+
const kids = childrenAccessor(node.data)
|
|
75
|
+
if (kids?.length) {
|
|
76
|
+
node.children = kids.map(d => ({
|
|
77
|
+
data: d,
|
|
78
|
+
children: null,
|
|
79
|
+
parent: node,
|
|
80
|
+
depth: node.depth + 1,
|
|
81
|
+
height: 0,
|
|
82
|
+
}))
|
|
83
|
+
for (const child of node.children) {
|
|
84
|
+
stack.push(child)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
52
87
|
}
|
|
53
|
-
return node
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function hierarchy<T>(
|
|
57
|
-
data: T,
|
|
58
|
-
childrenAccessor: (d: T) => T[] | undefined,
|
|
59
|
-
): HierarchyNode<T> {
|
|
60
|
-
const root = wrap(data, childrenAccessor, null, 0)
|
|
61
88
|
computeHeight(root)
|
|
62
89
|
return root
|
|
63
90
|
}
|
|
@@ -66,17 +93,17 @@ export function sum<T>(
|
|
|
66
93
|
node: HierarchyNode<T>,
|
|
67
94
|
valueFn: (d: T) => number,
|
|
68
95
|
): HierarchyNode<T> {
|
|
69
|
-
|
|
96
|
+
const nodes = descendants(node)
|
|
97
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
98
|
+
const n = nodes[i]!
|
|
70
99
|
let s = valueFn(n.data)
|
|
71
100
|
if (n.children) {
|
|
72
101
|
for (const child of n.children) {
|
|
73
|
-
s +=
|
|
102
|
+
s += child.value!
|
|
74
103
|
}
|
|
75
104
|
}
|
|
76
105
|
n.value = s
|
|
77
|
-
return s
|
|
78
106
|
}
|
|
79
|
-
visit(node)
|
|
80
107
|
return node
|
|
81
108
|
}
|
|
82
109
|
|
|
@@ -84,15 +111,16 @@ export function sort<T>(
|
|
|
84
111
|
node: HierarchyNode<T>,
|
|
85
112
|
compareFn: (a: HierarchyNode<T>, b: HierarchyNode<T>) => number,
|
|
86
113
|
): HierarchyNode<T> {
|
|
87
|
-
|
|
114
|
+
const stack = [node]
|
|
115
|
+
while (stack.length > 0) {
|
|
116
|
+
const n = stack.pop()!
|
|
88
117
|
if (n.children) {
|
|
89
118
|
n.children.sort(compareFn)
|
|
90
119
|
for (const child of n.children) {
|
|
91
|
-
|
|
120
|
+
stack.push(child)
|
|
92
121
|
}
|
|
93
122
|
}
|
|
94
123
|
}
|
|
95
|
-
visit(node)
|
|
96
124
|
return node
|
|
97
125
|
}
|
|
98
126
|
|
|
@@ -100,61 +128,69 @@ export function find<T>(
|
|
|
100
128
|
node: HierarchyNode<T>,
|
|
101
129
|
predicate: (n: HierarchyNode<T>) => boolean,
|
|
102
130
|
): HierarchyNode<T> | undefined {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
const stack = [node]
|
|
132
|
+
let found: HierarchyNode<T> | undefined
|
|
133
|
+
while (stack.length > 0 && found === undefined) {
|
|
134
|
+
const n = stack.pop()!
|
|
135
|
+
if (predicate(n)) {
|
|
136
|
+
found = n
|
|
137
|
+
} else if (n.children) {
|
|
138
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
139
|
+
stack.push(n.children[i]!)
|
|
111
140
|
}
|
|
112
141
|
}
|
|
113
142
|
}
|
|
114
|
-
return
|
|
143
|
+
return found
|
|
115
144
|
}
|
|
116
145
|
|
|
117
146
|
export function leaves<T>(node: HierarchyNode<T>): HierarchyNode<T>[] {
|
|
118
147
|
const result: HierarchyNode<T>[] = []
|
|
119
|
-
|
|
148
|
+
const stack = [node]
|
|
149
|
+
while (stack.length > 0) {
|
|
150
|
+
const n = stack.pop()!
|
|
120
151
|
if (n.children) {
|
|
121
|
-
for (
|
|
122
|
-
|
|
152
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
153
|
+
stack.push(n.children[i]!)
|
|
123
154
|
}
|
|
124
155
|
} else {
|
|
125
156
|
result.push(n)
|
|
126
157
|
}
|
|
127
158
|
}
|
|
128
|
-
visit(node)
|
|
129
159
|
return result
|
|
130
160
|
}
|
|
131
161
|
|
|
132
|
-
export function
|
|
133
|
-
const result:
|
|
134
|
-
|
|
135
|
-
result.push(
|
|
136
|
-
|
|
137
|
-
for (const child of n.children) {
|
|
138
|
-
visit(child)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
visit(node)
|
|
162
|
+
export function links<T>(node: HierarchyNode<T>): HierarchyLink<T>[] {
|
|
163
|
+
const result: HierarchyLink<T>[] = []
|
|
164
|
+
forEachLink(node, (source, target) => {
|
|
165
|
+
result.push({ source, target })
|
|
166
|
+
})
|
|
143
167
|
return result
|
|
144
168
|
}
|
|
145
169
|
|
|
146
|
-
export function
|
|
147
|
-
|
|
148
|
-
|
|
170
|
+
export function forEachLink<T>(
|
|
171
|
+
node: HierarchyNode<T>,
|
|
172
|
+
cb: (source: HierarchyNode<T>, target: HierarchyNode<T>) => void,
|
|
173
|
+
) {
|
|
174
|
+
const stack = [node]
|
|
175
|
+
while (stack.length > 0) {
|
|
176
|
+
const n = stack.pop()!
|
|
149
177
|
if (n.children) {
|
|
150
|
-
for (
|
|
151
|
-
|
|
152
|
-
|
|
178
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
179
|
+
const child = n.children[i]!
|
|
180
|
+
cb(n, child)
|
|
181
|
+
stack.push(child)
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
}
|
|
156
|
-
|
|
157
|
-
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function forEachDescendant<T>(
|
|
188
|
+
node: HierarchyNode<T>,
|
|
189
|
+
cb: (n: HierarchyNode<T>) => void,
|
|
190
|
+
) {
|
|
191
|
+
for (const n of descendants(node)) {
|
|
192
|
+
cb(n)
|
|
193
|
+
}
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
export function clusterLayout<T>(
|
|
@@ -170,31 +206,31 @@ export function clusterLayout<T>(
|
|
|
170
206
|
leafNodes[i]!.x = (i + 0.5) * step
|
|
171
207
|
}
|
|
172
208
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
209
|
+
// x of an internal node is the mean of its children's x, so process in
|
|
210
|
+
// post-order (children before parents)
|
|
211
|
+
const nodes = descendants(root)
|
|
212
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
213
|
+
const node = nodes[i]!
|
|
214
|
+
if (node.children) {
|
|
215
|
+
let sum = 0
|
|
216
|
+
for (const child of node.children) {
|
|
217
|
+
sum += child.x!
|
|
218
|
+
}
|
|
219
|
+
node.x = sum / node.children.length
|
|
183
220
|
}
|
|
184
|
-
node.x = sum / node.children.length
|
|
185
221
|
}
|
|
186
|
-
assignX(root)
|
|
187
222
|
|
|
188
223
|
const rootHeight = root.height
|
|
189
|
-
|
|
224
|
+
const stack = [{ node: root, depth: 0 }]
|
|
225
|
+
while (stack.length > 0) {
|
|
226
|
+
const { node, depth } = stack.pop()!
|
|
190
227
|
node.y = rootHeight === 0 ? sizeY : (depth / rootHeight) * sizeY
|
|
191
228
|
if (node.children) {
|
|
192
229
|
for (const child of node.children) {
|
|
193
|
-
|
|
230
|
+
stack.push({ node: child, depth: depth + 1 })
|
|
194
231
|
}
|
|
195
232
|
}
|
|
196
233
|
}
|
|
197
|
-
assignY(root, 0)
|
|
198
234
|
}
|
|
199
235
|
|
|
200
236
|
export function collapse<T>(node: HierarchyNode<T>) {
|
|
@@ -209,40 +245,57 @@ export function collapse<T>(node: HierarchyNode<T>) {
|
|
|
209
245
|
// x. Memoizes onto node.depthToLeaf since the layout walks the tree repeatedly.
|
|
210
246
|
// See https://github.com/emmanuelparadis/ape/blob/master/R/plot.phylo.R
|
|
211
247
|
export function calcDepthToLeaf(node: HierarchyNode): number {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
248
|
+
const nodes = descendants(node)
|
|
249
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
250
|
+
const n = nodes[i]!
|
|
251
|
+
if (n.depthToLeaf === undefined) {
|
|
252
|
+
let maxDepth = 0
|
|
253
|
+
if (n.children) {
|
|
254
|
+
for (const child of n.children) {
|
|
255
|
+
maxDepth = Math.max(maxDepth, 1 + child.depthToLeaf!)
|
|
256
|
+
}
|
|
217
257
|
}
|
|
258
|
+
n.depthToLeaf = maxDepth
|
|
218
259
|
}
|
|
219
|
-
node.depthToLeaf = maxDepth
|
|
220
260
|
}
|
|
221
|
-
return node.depthToLeaf
|
|
261
|
+
return node.depthToLeaf!
|
|
222
262
|
}
|
|
223
263
|
|
|
224
264
|
export function findMaxBranchLen(node: HierarchyNode): number {
|
|
225
|
-
let maxLen =
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
maxLen = Math.max(maxLen, findMaxBranchLen(child))
|
|
229
|
-
}
|
|
265
|
+
let maxLen = 0
|
|
266
|
+
for (const n of descendants(node)) {
|
|
267
|
+
maxLen = Math.max(maxLen, n.len || 0)
|
|
230
268
|
}
|
|
231
269
|
return maxLen
|
|
232
270
|
}
|
|
233
271
|
|
|
272
|
+
// Max root-to-leaf sum of branch lengths within the subtree at d
|
|
234
273
|
export function maxLength(d: HierarchyNode): number {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
274
|
+
const nodes = descendants(d)
|
|
275
|
+
const pathLen = new Map<HierarchyNode, number>()
|
|
276
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
277
|
+
const n = nodes[i]!
|
|
278
|
+
let childMax = 0
|
|
279
|
+
if (n.children) {
|
|
280
|
+
for (const child of n.children) {
|
|
281
|
+
childMax = Math.max(childMax, pathLen.get(child)!)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
pathLen.set(n, (n.data.length || 0) + childMax)
|
|
285
|
+
}
|
|
286
|
+
return pathLen.get(d)!
|
|
239
287
|
}
|
|
240
288
|
|
|
241
289
|
export function setBrLength(d: HierarchyNode, y0: number, k: number) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
290
|
+
const stack = [{ node: d, y0 }]
|
|
291
|
+
while (stack.length > 0) {
|
|
292
|
+
const { node, y0: acc } = stack.pop()!
|
|
293
|
+
const next = acc + Math.max(node.data.length || 0, 0)
|
|
294
|
+
node.len = next * k
|
|
295
|
+
if (node.children) {
|
|
296
|
+
for (const child of node.children) {
|
|
297
|
+
stack.push({ node: child, y0: next })
|
|
298
|
+
}
|
|
246
299
|
}
|
|
247
300
|
}
|
|
248
301
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// PUBLIC API — consumed by external JBrowse 2 plugins. Changing or removing any
|
|
2
|
+
// export here is a breaking change for downstream repos:
|
|
3
|
+
// - jbrowse-plugin-msaview (wraps MSAModelF + MSAView into a JBrowse view)
|
|
4
|
+
// - jbrowse-plugin-protein3d (drives MSA<->structure hover/highlight sync)
|
|
5
|
+
// Those plugins also reach into the MsaViewModel instance at runtime; the model
|
|
6
|
+
// members they rely on (e.g. mouseCol/setMousePos, setHighlightedColumns,
|
|
7
|
+
// seqPosToVisibleCol/visibleColToSeqPos) are flagged inline in model.ts.
|
|
8
|
+
export { renderToSvg } from './renderToSvg.tsx'
|
|
1
9
|
export { default as MSAView } from './components/Loading.tsx'
|
|
2
10
|
export { default as MSAViewer } from './components/MSAViewer.tsx'
|
|
3
11
|
export { type MsaViewModel, default as MSAModelF } from './model.ts'
|
|
@@ -73,21 +73,36 @@ async function wait({
|
|
|
73
73
|
signal?: AbortSignal
|
|
74
74
|
}) {
|
|
75
75
|
const url = `${base}/iprscan5/status/${jobId}`
|
|
76
|
+
// EBI jobs run for minutes; cap polling so an unexpected/stuck status can't
|
|
77
|
+
// spin forever (the abort signal is the normal early exit). ~10s per check.
|
|
78
|
+
const maxChecks = 360
|
|
76
79
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
let finished = false
|
|
81
|
+
for (let check = 0; check < maxChecks && !finished; check++) {
|
|
79
82
|
for (let i = 0; i < 10; i++) {
|
|
80
83
|
await timeout(1000, signal)
|
|
81
84
|
onProgress({ msg: `Checking status ${10 - i}`, url })
|
|
82
85
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
// status endpoint returns a bare status token; match exactly rather than
|
|
87
|
+
// substring so an error page mentioning "FINISHED" can't be a false hit
|
|
88
|
+
const status = (await textfetch(url, { signal })).trim()
|
|
89
|
+
if (status === 'FINISHED') {
|
|
90
|
+
finished = true
|
|
91
|
+
} else if (
|
|
92
|
+
status === 'FAILURE' ||
|
|
93
|
+
status === 'ERROR' ||
|
|
94
|
+
status === 'NOT_FOUND'
|
|
95
|
+
) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`InterProScan job ${jobId} ended with status: ${status}`,
|
|
98
|
+
)
|
|
89
99
|
}
|
|
90
100
|
}
|
|
101
|
+
if (!finished) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`InterProScan job ${jobId} did not finish after ${maxChecks} status checks`,
|
|
104
|
+
)
|
|
105
|
+
}
|
|
91
106
|
} finally {
|
|
92
107
|
onProgress()
|
|
93
108
|
}
|
|
@@ -152,10 +167,17 @@ async function loadInterProScanResultsWithStatus({
|
|
|
152
167
|
url: `https://www.ebi.ac.uk/Tools/services/rest/iprscan5/result/${jobId}/json`,
|
|
153
168
|
})
|
|
154
169
|
const ret = await loadInterProScanResults(jobId, signal)
|
|
155
|
-
|
|
156
|
-
|
|
170
|
+
// key each result by its xref id; skip any result lacking an xref entry
|
|
171
|
+
// rather than crashing the whole load on one malformed result
|
|
172
|
+
model.setDomains(
|
|
173
|
+
Object.fromEntries(
|
|
174
|
+
ret.results
|
|
175
|
+
.map(r => [r.xref[0]?.id, r] as const)
|
|
176
|
+
.filter(
|
|
177
|
+
(e): e is [string, InterProScanResults] => e[0] !== undefined,
|
|
178
|
+
),
|
|
179
|
+
),
|
|
157
180
|
)
|
|
158
|
-
model.setShowDomains(true)
|
|
159
181
|
getSession(model).notify(`Loaded interproscan ${jobId} results`, 'success')
|
|
160
182
|
} catch (e) {
|
|
161
183
|
if (isAbortError(e)) {
|
package/src/measureTextCanvas.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { setFontSize } from './setFontSize.ts'
|
|
2
|
+
|
|
1
3
|
let canvasHandle: HTMLCanvasElement | undefined
|
|
2
4
|
|
|
3
5
|
export function measureTextCanvas(text: string, fontSize: number) {
|
|
@@ -9,6 +11,6 @@ export function measureTextCanvas(text: string, fontSize: number) {
|
|
|
9
11
|
if (!ctx) {
|
|
10
12
|
throw new Error('no canvas context')
|
|
11
13
|
}
|
|
12
|
-
ctx
|
|
14
|
+
setFontSize(ctx, fontSize)
|
|
13
15
|
return ctx.measureText(text).width
|
|
14
16
|
}
|