react-msaview 5.0.6 → 5.0.13

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.
Files changed (190) hide show
  1. package/bundle/index.js +106 -106
  2. package/bundle/index.js.LICENSE.txt +1 -1
  3. package/bundle/index.js.map +1 -1
  4. package/dist/components/Checkbox2.js +3 -6
  5. package/dist/components/Checkbox2.js.map +1 -1
  6. package/dist/components/MSAViewer.d.ts +14 -0
  7. package/dist/components/MSAViewer.js +34 -0
  8. package/dist/components/MSAViewer.js.map +1 -0
  9. package/dist/components/Track.d.ts +0 -4
  10. package/dist/components/Track.js +6 -26
  11. package/dist/components/Track.js.map +1 -1
  12. package/dist/components/dialogs/DomainDialog.js +2 -5
  13. package/dist/components/dialogs/DomainDialog.js.map +1 -1
  14. package/dist/components/dialogs/InterProScanDialog.js +7 -7
  15. package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
  16. package/dist/components/dialogs/SettingsDialog.js +3 -19
  17. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  18. package/dist/components/header/ColorSchemeMenu.d.ts +6 -0
  19. package/dist/components/header/ColorSchemeMenu.js +19 -0
  20. package/dist/components/header/ColorSchemeMenu.js.map +1 -0
  21. package/dist/components/header/{ZoomStar.d.ts → FileMenu.d.ts} +2 -2
  22. package/dist/components/header/FileMenu.js +71 -0
  23. package/dist/components/header/FileMenu.js.map +1 -0
  24. package/dist/components/header/Header.js +8 -6
  25. package/dist/components/header/Header.js.map +1 -1
  26. package/dist/components/header/HeaderMenu.js +3 -145
  27. package/dist/components/header/HeaderMenu.js.map +1 -1
  28. package/dist/components/header/MSASettingsMenu.d.ts +6 -0
  29. package/dist/components/header/MSASettingsMenu.js +36 -0
  30. package/dist/components/header/MSASettingsMenu.js.map +1 -0
  31. package/dist/components/header/SettingsMenu.js +1 -21
  32. package/dist/components/header/SettingsMenu.js.map +1 -1
  33. package/dist/components/header/TreeSettingsMenu.d.ts +6 -0
  34. package/dist/components/header/TreeSettingsMenu.js +74 -0
  35. package/dist/components/header/TreeSettingsMenu.js.map +1 -0
  36. package/dist/components/header/ZoomMenu.js +0 -8
  37. package/dist/components/header/ZoomMenu.js.map +1 -1
  38. package/dist/components/header/getDomainsMenu.d.ts +31 -0
  39. package/dist/components/header/getDomainsMenu.js +75 -0
  40. package/dist/components/header/getDomainsMenu.js.map +1 -0
  41. package/dist/components/import/ImportFormExamples.js +21 -19
  42. package/dist/components/import/ImportFormExamples.js.map +1 -1
  43. package/dist/components/msa/MSACanvas.js +13 -89
  44. package/dist/components/msa/MSACanvas.js.map +1 -1
  45. package/dist/components/msa/MSACanvasBlock.js +1 -3
  46. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  47. package/dist/components/msa/renderMSABlock.js +2 -4
  48. package/dist/components/msa/renderMSABlock.js.map +1 -1
  49. package/dist/components/msa/renderMSAMouseover.js +1 -7
  50. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  51. package/dist/components/tree/TreeCanvas.js +18 -101
  52. package/dist/components/tree/TreeCanvas.js.map +1 -1
  53. package/dist/components/tree/TreeCanvasBlock.js +33 -1
  54. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  55. package/dist/components/tree/TreeNodeMenu.js +5 -16
  56. package/dist/components/tree/TreeNodeMenu.js.map +1 -1
  57. package/dist/components/tree/renderTreeCanvas.js +4 -12
  58. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  59. package/dist/constants.d.ts +0 -2
  60. package/dist/constants.js +0 -2
  61. package/dist/constants.js.map +1 -1
  62. package/dist/fetchUtils.d.ts +0 -1
  63. package/dist/fetchUtils.js +0 -4
  64. package/dist/fetchUtils.js.map +1 -1
  65. package/dist/flatToTree.d.ts +0 -5
  66. package/dist/flatToTree.js +13 -30
  67. package/dist/flatToTree.js.map +1 -1
  68. package/dist/hierarchy.d.ts +28 -0
  69. package/dist/hierarchy.js +164 -0
  70. package/dist/hierarchy.js.map +1 -0
  71. package/dist/index.d.ts +2 -0
  72. package/dist/index.js +1 -0
  73. package/dist/index.js.map +1 -1
  74. package/dist/launchInterProScan.d.ts +0 -5
  75. package/dist/launchInterProScan.js +5 -3
  76. package/dist/launchInterProScan.js.map +1 -1
  77. package/dist/model/DataModel.d.ts +9 -0
  78. package/dist/model/DataModel.js +12 -1
  79. package/dist/model/DataModel.js.map +1 -1
  80. package/dist/model/msaModel.d.ts +3 -0
  81. package/dist/model/msaModel.js +0 -1
  82. package/dist/model/msaModel.js.map +1 -1
  83. package/dist/model/treeModel.d.ts +3 -6
  84. package/dist/model/treeModel.js +3 -15
  85. package/dist/model/treeModel.js.map +1 -1
  86. package/dist/model.d.ts +34 -77
  87. package/dist/model.js +140 -239
  88. package/dist/model.js.map +1 -1
  89. package/dist/neighborJoining.js +40 -633
  90. package/dist/neighborJoining.js.map +1 -1
  91. package/dist/parseAsn1.d.ts +0 -12
  92. package/dist/parseAsn1.js +125 -332
  93. package/dist/parseAsn1.js.map +1 -1
  94. package/dist/useWheelScroll.d.ts +8 -0
  95. package/dist/useWheelScroll.js +93 -0
  96. package/dist/useWheelScroll.js.map +1 -0
  97. package/dist/util.d.ts +1 -6
  98. package/dist/util.js +5 -34
  99. package/dist/util.js.map +1 -1
  100. package/dist/vendor/copyToClipboard.d.ts +1 -10
  101. package/dist/vendor/copyToClipboard.js +14 -109
  102. package/dist/vendor/copyToClipboard.js.map +1 -1
  103. package/dist/vendor/fileSaver.d.ts +1 -11
  104. package/dist/vendor/fileSaver.js +7 -76
  105. package/dist/vendor/fileSaver.js.map +1 -1
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/dist/version.js.map +1 -1
  109. package/package.json +14 -14
  110. package/src/collapseLogic.test.ts +115 -0
  111. package/src/components/Checkbox2.tsx +9 -18
  112. package/src/components/MSAViewer.tsx +67 -0
  113. package/src/components/Track.tsx +11 -30
  114. package/src/components/dialogs/DomainDialog.tsx +4 -5
  115. package/src/components/dialogs/InterProScanDialog.tsx +7 -7
  116. package/src/components/dialogs/SettingsDialog.tsx +0 -37
  117. package/src/components/header/ColorSchemeMenu.tsx +35 -0
  118. package/src/components/header/FileMenu.tsx +84 -0
  119. package/src/components/header/Header.tsx +8 -6
  120. package/src/components/header/HeaderMenu.tsx +4 -155
  121. package/src/components/header/MSASettingsMenu.tsx +48 -0
  122. package/src/components/header/SettingsMenu.tsx +0 -23
  123. package/src/components/header/TreeSettingsMenu.tsx +96 -0
  124. package/src/components/header/ZoomMenu.tsx +0 -8
  125. package/src/components/header/getDomainsMenu.ts +83 -0
  126. package/src/components/import/ImportFormExamples.tsx +37 -34
  127. package/src/components/msa/MSACanvas.tsx +21 -97
  128. package/src/components/msa/MSACanvasBlock.tsx +1 -3
  129. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +1 -1
  130. package/src/components/msa/renderMSABlock.ts +2 -5
  131. package/src/components/msa/renderMSAMouseover.ts +0 -6
  132. package/src/components/tree/TreeCanvas.tsx +48 -111
  133. package/src/components/tree/TreeCanvasBlock.tsx +44 -0
  134. package/src/components/tree/TreeNodeMenu.tsx +5 -14
  135. package/src/components/tree/renderTreeCanvas.ts +8 -21
  136. package/src/constants.ts +0 -2
  137. package/src/fetchUtils.ts +0 -5
  138. package/src/flatToTree.ts +20 -38
  139. package/src/hierarchy.test.ts +120 -0
  140. package/src/hierarchy.ts +220 -0
  141. package/src/index.ts +2 -0
  142. package/src/launchInterProScan.ts +4 -3
  143. package/src/model/DataModel.ts +12 -1
  144. package/src/model/msaModel.ts +0 -2
  145. package/src/model/treeModel.ts +2 -18
  146. package/src/model.ts +203 -278
  147. package/src/neighborJoining.test.ts +15 -7
  148. package/src/neighborJoining.ts +40 -632
  149. package/src/parseAsn1.test.ts +5 -2
  150. package/src/parseAsn1.ts +135 -405
  151. package/src/useWheelScroll.ts +109 -0
  152. package/src/util.ts +5 -50
  153. package/src/vendor/copyToClipboard.ts +14 -122
  154. package/src/vendor/fileSaver.ts +8 -105
  155. package/src/version.ts +1 -1
  156. package/dist/components/dialogs/AddTrackDialog.d.ts +0 -8
  157. package/dist/components/dialogs/AddTrackDialog.js +0 -30
  158. package/dist/components/dialogs/AddTrackDialog.js.map +0 -1
  159. package/dist/components/dialogs/TabPanel.d.ts +0 -6
  160. package/dist/components/dialogs/TabPanel.js +0 -6
  161. package/dist/components/dialogs/TabPanel.js.map +0 -1
  162. package/dist/components/header/ZoomStar.js +0 -40
  163. package/dist/components/header/ZoomStar.js.map +0 -1
  164. package/dist/createPaletteMap.test.d.ts +0 -1
  165. package/dist/createPaletteMap.test.js +0 -49
  166. package/dist/createPaletteMap.test.js.map +0 -1
  167. package/dist/layout.d.ts +0 -26
  168. package/dist/layout.js +0 -74
  169. package/dist/layout.js.map +0 -1
  170. package/dist/neighborJoining.test.d.ts +0 -1
  171. package/dist/neighborJoining.test.js +0 -110
  172. package/dist/neighborJoining.test.js.map +0 -1
  173. package/dist/parseAsn1.test.d.ts +0 -1
  174. package/dist/parseAsn1.test.js +0 -8
  175. package/dist/parseAsn1.test.js.map +0 -1
  176. package/dist/reparseTree.d.ts +0 -2
  177. package/dist/reparseTree.js +0 -15
  178. package/dist/reparseTree.js.map +0 -1
  179. package/dist/rowCoordinateCalculations.test.d.ts +0 -1
  180. package/dist/rowCoordinateCalculations.test.js +0 -224
  181. package/dist/rowCoordinateCalculations.test.js.map +0 -1
  182. package/dist/seqPosToGlobalCol.test.d.ts +0 -1
  183. package/dist/seqPosToGlobalCol.test.js +0 -60
  184. package/dist/seqPosToGlobalCol.test.js.map +0 -1
  185. package/src/components/dialogs/AddTrackDialog.tsx +0 -85
  186. package/src/components/dialogs/TabPanel.tsx +0 -19
  187. package/src/components/header/ZoomStar.tsx +0 -74
  188. package/src/createPaletteMap.test.ts +0 -57
  189. package/src/layout.ts +0 -118
  190. package/src/reparseTree.ts +0 -18
package/src/flatToTree.ts CHANGED
@@ -1,10 +1,8 @@
1
- // Define the input item interface
2
1
  interface FlatItem {
3
2
  id: number
4
3
  parent?: number
5
4
  }
6
5
 
7
- // Define the tree node interface
8
6
  interface TreeNode {
9
7
  id: string
10
8
  name: string
@@ -12,46 +10,30 @@ interface TreeNode {
12
10
  children: TreeNode[]
13
11
  }
14
12
 
15
- /**
16
- * Parses a flat list of items into a tree structure
17
- * @param items - Array of flat items with id and optional parent
18
- * @returns Array of root tree nodes
19
- */
20
13
  export function flatToTree(items: FlatItem[]): TreeNode {
21
- // Create a map to store all nodes by their id for quick lookup
22
- const nodeMap = new Map<number, TreeNode>()
14
+ const nodeMap = new Map(
15
+ items.map(item => [
16
+ item.id,
17
+ {
18
+ id: `${item.id}`,
19
+ name: `${item.id}`,
20
+ parent: item.parent !== undefined ? `${item.parent}` : undefined,
21
+ children: [] as TreeNode[],
22
+ },
23
+ ]),
24
+ )
23
25
 
24
- // First pass: Create all tree nodes
25
- items.forEach(item => {
26
- nodeMap.set(item.id, {
27
- ...item,
28
- id: `${item.id}`,
29
- name: `${item.id}`,
30
- parent: item.parent !== undefined ? `${item.parent}` : undefined,
31
- children: [],
32
- })
33
- })
34
-
35
- // Second pass: Build parent-child relationships
36
- const roots: TreeNode[] = []
37
-
38
- items.forEach(item => {
26
+ let root: TreeNode | undefined
27
+ for (const item of items) {
39
28
  const node = nodeMap.get(item.id)!
40
-
41
- if (item.parent !== undefined) {
42
- // This item has a parent, add it to parent's children
43
- const parentNode = nodeMap.get(item.parent)
44
- if (parentNode) {
45
- parentNode.children.push(node)
46
- } else {
47
- // Parent doesn't exist, treat as root
48
- roots.push(node)
49
- }
29
+ const parent =
30
+ item.parent !== undefined ? nodeMap.get(item.parent) : undefined
31
+ if (parent) {
32
+ parent.children.push(node)
50
33
  } else {
51
- // This item has no parent, it's a root node
52
- roots.push(node)
34
+ root ??= node
53
35
  }
54
- })
36
+ }
55
37
 
56
- return roots[0]!
38
+ return root!
57
39
  }
@@ -0,0 +1,120 @@
1
+ import { describe, expect, test } from 'vitest'
2
+
3
+ import { collapse, find, hierarchy, leaves, sort, sum } from './hierarchy.ts'
4
+
5
+ import type { NodeWithIds } from './types.ts'
6
+
7
+ function makeTree(): NodeWithIds {
8
+ return {
9
+ id: 'root',
10
+ name: 'root',
11
+ children: [
12
+ {
13
+ id: 'A',
14
+ name: 'A',
15
+ children: [
16
+ { id: 'A1', name: 'A1', children: [] },
17
+ { id: 'A2', name: 'A2', children: [] },
18
+ ],
19
+ },
20
+ {
21
+ id: 'B',
22
+ name: 'B',
23
+ children: [
24
+ { id: 'B1', name: 'B1', children: [] },
25
+ { id: 'B2', name: 'B2', children: [] },
26
+ ],
27
+ },
28
+ ],
29
+ }
30
+ }
31
+
32
+ describe('hierarchy', () => {
33
+ test('builds hierarchy from tree data', () => {
34
+ const h = hierarchy(makeTree(), d => d.children)
35
+ expect(h.data.id).toBe('root')
36
+ expect(h.children?.length).toBe(2)
37
+ expect(h.height).toBe(2)
38
+ })
39
+
40
+ test('sets parent references', () => {
41
+ const h = hierarchy(makeTree(), d => d.children)
42
+ expect(h.parent).toBeNull()
43
+ expect(h.children![0]!.parent).toBe(h)
44
+ expect(h.children![0]!.children![0]!.parent).toBe(h.children![0])
45
+ })
46
+ })
47
+
48
+ describe('leaves', () => {
49
+ test('returns leaf nodes', () => {
50
+ const h = hierarchy(makeTree(), d => d.children)
51
+ const l = leaves(h)
52
+ expect(l.map(n => n.data.name)).toEqual(['A1', 'A2', 'B1', 'B2'])
53
+ })
54
+ })
55
+
56
+ describe('find', () => {
57
+ test('finds node by id', () => {
58
+ const h = hierarchy(makeTree(), d => d.children)
59
+ const node = find(h, n => n.data.id === 'B1')
60
+ expect(node?.data.name).toBe('B1')
61
+ })
62
+
63
+ test('returns undefined for missing id', () => {
64
+ const h = hierarchy(makeTree(), d => d.children)
65
+ expect(find(h, n => n.data.id === 'Z')).toBeUndefined()
66
+ })
67
+ })
68
+
69
+ describe('collapse', () => {
70
+ test('hides children of a branch node', () => {
71
+ const h = hierarchy(makeTree(), d => d.children)
72
+ const nodeA = find(h, n => n.data.id === 'A')!
73
+ collapse(nodeA)
74
+ expect(nodeA.children).toBeNull()
75
+ expect(nodeA._children?.length).toBe(2)
76
+ expect(leaves(h).map(n => n.data.name)).toEqual(['A', 'B1', 'B2'])
77
+ })
78
+
79
+ test('does nothing on a leaf node', () => {
80
+ const h = hierarchy(makeTree(), d => d.children)
81
+ const leaf = find(h, n => n.data.id === 'A1')!
82
+ collapse(leaf)
83
+ expect(leaves(h).map(n => n.data.name)).toEqual(['A1', 'A2', 'B1', 'B2'])
84
+ })
85
+ })
86
+
87
+ describe('leaf removal via parent.children filter', () => {
88
+ test('removing a leaf from its parent hides it from leaves()', () => {
89
+ const h = hierarchy(makeTree(), d => d.children)
90
+ const leaf = find(h, n => n.data.id === 'A1')!
91
+ leaf.parent!.children = leaf.parent!.children!.filter(
92
+ c => c.data.id !== 'A1',
93
+ )
94
+ expect(leaves(h).map(n => n.data.name)).toEqual(['A2', 'B1', 'B2'])
95
+ })
96
+
97
+ test('removing all leaves from a branch makes the branch a leaf', () => {
98
+ const h = hierarchy(makeTree(), d => d.children)
99
+ const nodeA = find(h, n => n.data.id === 'A')!
100
+ nodeA.children = []
101
+ expect(leaves(h).map(n => n.data.name)).toEqual(['B1', 'B2'])
102
+ })
103
+ })
104
+
105
+ describe('sort', () => {
106
+ test('sorts children', () => {
107
+ const h = hierarchy(makeTree(), d => d.children)
108
+ sort(h, (a, b) => b.data.name.localeCompare(a.data.name))
109
+ expect(h.children!.map(c => c.data.name)).toEqual(['B', 'A'])
110
+ })
111
+ })
112
+
113
+ describe('sum', () => {
114
+ test('computes leaf counts', () => {
115
+ const h = hierarchy(makeTree(), d => d.children)
116
+ sum(h, d => (d.children.length > 0 ? 0 : 1))
117
+ expect(h.value).toBe(4)
118
+ expect(find(h, n => n.data.id === 'A')?.value).toBe(2)
119
+ })
120
+ })
@@ -0,0 +1,220 @@
1
+ import type { NodeWithIds } from './types.ts'
2
+
3
+ export interface HierarchyNode<T = NodeWithIds> {
4
+ data: T
5
+ children: HierarchyNode<T>[] | null
6
+ parent: HierarchyNode<T> | null
7
+ depth: number
8
+ height: number
9
+ value?: number
10
+ x?: number
11
+ y?: number
12
+ len?: number
13
+ _children?: HierarchyNode<T>[] | null
14
+ }
15
+
16
+ export interface HierarchyLink<T = NodeWithIds> {
17
+ source: HierarchyNode<T>
18
+ target: HierarchyNode<T>
19
+ }
20
+
21
+ function computeHeight<T>(node: HierarchyNode<T>): number {
22
+ let h = 0
23
+ if (node.children) {
24
+ for (const child of node.children) {
25
+ const ch = computeHeight(child) + 1
26
+ if (ch > h) {
27
+ h = ch
28
+ }
29
+ }
30
+ }
31
+ node.height = h
32
+ return h
33
+ }
34
+
35
+ function wrap<T>(
36
+ data: T,
37
+ childrenAccessor: (d: T) => T[] | undefined,
38
+ parent: HierarchyNode<T> | null,
39
+ depth: number,
40
+ ): HierarchyNode<T> {
41
+ const kids = childrenAccessor(data)
42
+ const node: HierarchyNode<T> = {
43
+ data,
44
+ children: null,
45
+ parent,
46
+ depth,
47
+ height: 0,
48
+ }
49
+ if (kids?.length) {
50
+ node.children = kids.map(d => wrap(d, childrenAccessor, node, depth + 1))
51
+ }
52
+ return node
53
+ }
54
+
55
+ export function hierarchy<T>(
56
+ data: T,
57
+ childrenAccessor: (d: T) => T[] | undefined,
58
+ ): HierarchyNode<T> {
59
+ const root = wrap(data, childrenAccessor, null, 0)
60
+ computeHeight(root)
61
+ return root
62
+ }
63
+
64
+ export function sum<T>(
65
+ node: HierarchyNode<T>,
66
+ valueFn: (d: T) => number,
67
+ ): HierarchyNode<T> {
68
+ function visit(n: HierarchyNode<T>): number {
69
+ let s = valueFn(n.data)
70
+ if (n.children) {
71
+ for (const child of n.children) {
72
+ s += visit(child)
73
+ }
74
+ }
75
+ n.value = s
76
+ return s
77
+ }
78
+ visit(node)
79
+ return node
80
+ }
81
+
82
+ export function sort<T>(
83
+ node: HierarchyNode<T>,
84
+ compareFn: (a: HierarchyNode<T>, b: HierarchyNode<T>) => number,
85
+ ): HierarchyNode<T> {
86
+ function visit(n: HierarchyNode<T>) {
87
+ if (n.children) {
88
+ n.children.sort(compareFn)
89
+ for (const child of n.children) {
90
+ visit(child)
91
+ }
92
+ }
93
+ }
94
+ visit(node)
95
+ return node
96
+ }
97
+
98
+ export function find<T>(
99
+ node: HierarchyNode<T>,
100
+ predicate: (n: HierarchyNode<T>) => boolean,
101
+ ): HierarchyNode<T> | undefined {
102
+ if (predicate(node)) {
103
+ return node
104
+ }
105
+ if (node.children) {
106
+ for (const child of node.children) {
107
+ const result = find(child, predicate)
108
+ if (result) {
109
+ return result
110
+ }
111
+ }
112
+ }
113
+ return undefined
114
+ }
115
+
116
+ export function leaves<T>(node: HierarchyNode<T>): HierarchyNode<T>[] {
117
+ const result: HierarchyNode<T>[] = []
118
+ function visit(n: HierarchyNode<T>) {
119
+ if (n.children) {
120
+ for (const child of n.children) {
121
+ visit(child)
122
+ }
123
+ } else {
124
+ result.push(n)
125
+ }
126
+ }
127
+ visit(node)
128
+ return result
129
+ }
130
+
131
+ export function descendants<T>(node: HierarchyNode<T>): HierarchyNode<T>[] {
132
+ const result: HierarchyNode<T>[] = []
133
+ function visit(n: HierarchyNode<T>) {
134
+ result.push(n)
135
+ if (n.children) {
136
+ for (const child of n.children) {
137
+ visit(child)
138
+ }
139
+ }
140
+ }
141
+ visit(node)
142
+ return result
143
+ }
144
+
145
+ export function links<T>(node: HierarchyNode<T>): HierarchyLink<T>[] {
146
+ const result: HierarchyLink<T>[] = []
147
+ function visit(n: HierarchyNode<T>) {
148
+ if (n.children) {
149
+ for (const child of n.children) {
150
+ result.push({ source: n, target: child })
151
+ visit(child)
152
+ }
153
+ }
154
+ }
155
+ visit(node)
156
+ return result
157
+ }
158
+
159
+ export function clusterLayout<T>(
160
+ root: HierarchyNode<T>,
161
+ sizeX: number,
162
+ sizeY: number,
163
+ ) {
164
+ const leafNodes = leaves(root)
165
+ const n = leafNodes.length
166
+ const step = sizeX / n
167
+
168
+ for (let i = 0; i < n; i++) {
169
+ leafNodes[i]!.x = (i + 0.5) * step
170
+ }
171
+
172
+ function assignX(node: HierarchyNode<T>) {
173
+ if (!node.children) {
174
+ return
175
+ }
176
+ for (const child of node.children) {
177
+ assignX(child)
178
+ }
179
+ let sum = 0
180
+ for (const child of node.children) {
181
+ sum += child.x!
182
+ }
183
+ node.x = sum / node.children.length
184
+ }
185
+ assignX(root)
186
+
187
+ const rootHeight = root.height
188
+ function assignY(node: HierarchyNode<T>, depth: number) {
189
+ node.y = rootHeight === 0 ? sizeY : (depth / rootHeight) * sizeY
190
+ if (node.children) {
191
+ for (const child of node.children) {
192
+ assignY(child, depth + 1)
193
+ }
194
+ }
195
+ }
196
+ assignY(root, 0)
197
+ }
198
+
199
+ export function collapse<T>(node: HierarchyNode<T>) {
200
+ if (node.children) {
201
+ node._children = node.children
202
+ node.children = null
203
+ }
204
+ }
205
+
206
+ export function maxLength(d: HierarchyNode): number {
207
+ return (
208
+ (d.data.length || 0) +
209
+ (d.children ? d.children.reduce((m, c) => Math.max(m, maxLength(c)), 0) : 0)
210
+ )
211
+ }
212
+
213
+ export function setBrLength(d: HierarchyNode, y0: number, k: number) {
214
+ d.len = (y0 += Math.max(d.data.length || 0, 0)) * k
215
+ if (d.children) {
216
+ for (const child of d.children) {
217
+ setBrLength(child, y0, k)
218
+ }
219
+ }
220
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { default as MSAView } from './components/Loading.tsx'
2
+ export { default as MSAViewer } from './components/MSAViewer.tsx'
2
3
  export { type MsaViewModel, default as MSAModelF } from './model.ts'
3
4
  export type { MSAParserType } from 'msa-parsers'
5
+ export type { HierarchyNode } from './hierarchy.ts'
4
6
  export type { InterProScanResults } from './launchInterProScan.ts'
5
7
  export type {
6
8
  Accession,
@@ -52,7 +52,7 @@ async function runInterProScan({
52
52
  await loadInterProScanResultsWithStatus({ jobId, model })
53
53
  }
54
54
 
55
- export function loadInterProScanResults(jobId: string) {
55
+ function loadInterProScanResults(jobId: string) {
56
56
  return jsonfetch<InterProScanResponse>(
57
57
  `${base}/iprscan5/result/${jobId}/json`,
58
58
  )
@@ -111,14 +111,15 @@ export async function launchInterProScan({
111
111
  programs,
112
112
  model,
113
113
  })
114
+ } else {
115
+ throw new Error('unknown algorithm')
114
116
  }
115
- throw new Error('unknown algorithm')
116
117
  } finally {
117
118
  onProgress()
118
119
  }
119
120
  }
120
121
 
121
- export async function loadInterProScanResultsWithStatus({
122
+ async function loadInterProScanResultsWithStatus({
122
123
  jobId,
123
124
  model,
124
125
  }: {
@@ -22,6 +22,10 @@ export function DataModelF() {
22
22
  * #property
23
23
  */
24
24
  treeMetadata: types.maybe(types.string),
25
+ /**
26
+ * #property
27
+ */
28
+ gff: types.maybe(types.string),
25
29
  })
26
30
  .actions(self => ({
27
31
  /**
@@ -42,15 +46,22 @@ export function DataModelF() {
42
46
  setTreeMetadata(treeMetadata?: string) {
43
47
  self.treeMetadata = treeMetadata
44
48
  },
49
+ /**
50
+ * #action
51
+ */
52
+ setGFF(gff?: string) {
53
+ self.gff = gff
54
+ },
45
55
  }))
46
56
  .postProcessSnapshot(snap => {
47
- const { tree, msa, treeMetadata } = snap
57
+ const { tree, msa, treeMetadata, gff } = snap
48
58
  const max = 50_000
49
59
  return {
50
60
  tree: tree && tree.length > max ? undefined : tree,
51
61
  msa: msa && msa.length > max ? undefined : msa,
52
62
  treeMetadata:
53
63
  treeMetadata && treeMetadata.length > max ? undefined : treeMetadata,
64
+ gff: gff && gff.length > max ? undefined : gff,
54
65
  }
55
66
  })
56
67
  }
@@ -5,8 +5,6 @@ import { defaultBgColor, defaultColorSchemeName } from '../constants.ts'
5
5
  /**
6
6
  * #stateModel MSAModel
7
7
  */
8
- function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
9
-
10
8
  export function MSAModelF() {
11
9
  return types
12
10
  .model({
@@ -8,14 +8,11 @@ import {
8
8
  defaultShowBranchLen,
9
9
  defaultTreeAreaWidth,
10
10
  defaultTreeWidth,
11
- defaultTreeWidthMatchesArea,
12
11
  } from '../constants.ts'
13
12
 
14
13
  /**
15
14
  * #stateModel Tree
16
15
  */
17
- function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
18
-
19
16
  export function TreeModelF() {
20
17
  return types
21
18
  .model({
@@ -37,16 +34,11 @@ export function TreeModelF() {
37
34
 
38
35
  /**
39
36
  * #property
40
- * width of the tree within the treeArea, px
37
+ * width of the tree within the treeArea, px. automatically synced to
38
+ * fit within treeAreaWidth
41
39
  */
42
40
  treeWidth: types.optional(types.number, defaultTreeWidth),
43
41
 
44
- /**
45
- * #getter
46
- * synchronization that matches treeWidth to treeAreaWidth
47
- */
48
- treeWidthMatchesArea: defaultTreeWidthMatchesArea,
49
-
50
42
  /**
51
43
  * #property
52
44
  * use "branch length" e.g. evolutionary distance to draw tree branch
@@ -68,14 +60,6 @@ export function TreeModelF() {
68
60
  drawNodeBubbles: defaultDrawNodeBubbles,
69
61
  })
70
62
  .actions(self => ({
71
- /**
72
- * #action
73
- * synchronize the treewidth and treeareawidth
74
- */
75
- setTreeWidthMatchesArea(arg: boolean) {
76
- self.treeWidthMatchesArea = arg
77
- },
78
-
79
63
  /**
80
64
  * #action
81
65
  * set tree area width (px)