react-msaview 3.1.7 → 3.1.8

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 (270) hide show
  1. package/bundle/index.js +32 -32
  2. package/dist/components/Checkbox2.d.ts +7 -0
  3. package/dist/components/Checkbox2.js +10 -0
  4. package/dist/components/Checkbox2.js.map +1 -0
  5. package/dist/components/Loading.js +12 -4
  6. package/dist/components/Loading.js.map +1 -1
  7. package/dist/components/MSAView.js +5 -8
  8. package/dist/components/MSAView.js.map +1 -1
  9. package/dist/components/SequenceTextArea.d.ts +4 -0
  10. package/dist/components/SequenceTextArea.js +38 -0
  11. package/dist/components/SequenceTextArea.js.map +1 -0
  12. package/dist/components/Track.js +9 -8
  13. package/dist/components/Track.js.map +1 -1
  14. package/dist/components/dialogs/AddTrackDialog.js +0 -1
  15. package/dist/components/dialogs/AddTrackDialog.js.map +1 -1
  16. package/dist/components/{ExportSVGDialog.d.ts → dialogs/ExportSVGDialog.d.ts} +1 -1
  17. package/dist/components/{ExportSVGDialog.js → dialogs/ExportSVGDialog.js} +3 -4
  18. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -0
  19. package/dist/components/dialogs/FeatureDialog.d.ts +7 -0
  20. package/dist/components/dialogs/FeatureDialog.js +52 -0
  21. package/dist/components/dialogs/FeatureDialog.js.map +1 -0
  22. package/dist/components/dialogs/InterProScanDialog.d.ts +7 -0
  23. package/dist/components/dialogs/InterProScanDialog.js +163 -0
  24. package/dist/components/dialogs/InterProScanDialog.js.map +1 -0
  25. package/dist/components/dialogs/MetadataDialog.js +6 -3
  26. package/dist/components/dialogs/MetadataDialog.js.map +1 -1
  27. package/dist/components/dialogs/SettingsDialog.js +6 -11
  28. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  29. package/dist/components/{Header.d.ts → header/Header.d.ts} +1 -1
  30. package/dist/components/header/Header.js +30 -0
  31. package/dist/components/header/Header.js.map +1 -0
  32. package/dist/components/{HeaderInfoArea.d.ts → header/HeaderInfoArea.d.ts} +2 -2
  33. package/dist/components/header/HeaderInfoArea.js +20 -0
  34. package/dist/components/header/HeaderInfoArea.js.map +1 -0
  35. package/dist/components/header/HeaderMenu.d.ts +6 -0
  36. package/dist/components/header/HeaderMenu.js +40 -0
  37. package/dist/components/header/HeaderMenu.js.map +1 -0
  38. package/dist/components/header/HeaderMenuExtra.d.ts +6 -0
  39. package/dist/components/header/HeaderMenuExtra.js +92 -0
  40. package/dist/components/header/HeaderMenuExtra.js.map +1 -0
  41. package/dist/components/header/HeaderStatusArea.d.ts +6 -0
  42. package/dist/components/header/HeaderStatusArea.js +20 -0
  43. package/dist/components/header/HeaderStatusArea.js.map +1 -0
  44. package/dist/components/{MultiAlignmentSelector.d.ts → header/MultiAlignmentSelector.d.ts} +1 -1
  45. package/dist/components/header/MultiAlignmentSelector.js.map +1 -0
  46. package/dist/components/{ZoomControls.d.ts → header/ZoomControls.d.ts} +1 -1
  47. package/dist/components/header/ZoomControls.js +15 -0
  48. package/dist/components/header/ZoomControls.js.map +1 -0
  49. package/dist/components/{ImportForm/index.js → import/ImportForm.js} +1 -1
  50. package/dist/components/import/ImportForm.js.map +1 -0
  51. package/dist/components/{ImportForm → import}/ImportFormExamples.js +6 -2
  52. package/dist/components/import/ImportFormExamples.js.map +1 -0
  53. package/dist/components/import/data/seq2.js.map +1 -0
  54. package/dist/components/import/util.js +10 -0
  55. package/dist/components/import/util.js.map +1 -0
  56. package/dist/components/{Minimap.d.ts → minimap/Minimap.d.ts} +1 -1
  57. package/dist/components/minimap/Minimap.js.map +1 -0
  58. package/dist/components/{MinimapSVG.d.ts → minimap/MinimapSVG.d.ts} +1 -1
  59. package/dist/components/minimap/MinimapSVG.js.map +1 -0
  60. package/dist/components/msa/Loading.js.map +1 -0
  61. package/dist/components/{MSAPanel → msa}/MSACanvas.js +3 -2
  62. package/dist/components/msa/MSACanvas.js.map +1 -0
  63. package/dist/components/{MSAPanel/MSABlock.js → msa/MSACanvasBlock.js} +21 -9
  64. package/dist/components/msa/MSACanvasBlock.js.map +1 -0
  65. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -0
  66. package/dist/components/msa/MSAPanel.d.ts +6 -0
  67. package/dist/components/{MSAPanel/index.js → msa/MSAPanel.js} +6 -3
  68. package/dist/components/msa/MSAPanel.js.map +1 -0
  69. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +9 -0
  70. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +44 -0
  71. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -0
  72. package/dist/components/{MSAPanel → msa}/renderMSABlock.js +24 -20
  73. package/dist/components/msa/renderMSABlock.js.map +1 -0
  74. package/dist/components/msa/renderMSAMouseover.js.map +1 -0
  75. package/dist/components/tree/TreeBranchMenu.js.map +1 -0
  76. package/dist/components/{TreePanel → tree}/TreeCanvas.js +1 -1
  77. package/dist/components/tree/TreeCanvas.js.map +1 -0
  78. package/dist/components/{TreePanel → tree}/TreeCanvasBlock.js +1 -1
  79. package/dist/components/tree/TreeCanvasBlock.js.map +1 -0
  80. package/dist/components/{TreePanel → tree}/TreeNodeMenu.js +2 -33
  81. package/dist/components/tree/TreeNodeMenu.js.map +1 -0
  82. package/dist/components/{TreePanel/index.js → tree/TreePanel.js} +2 -2
  83. package/dist/components/tree/TreePanel.js.map +1 -0
  84. package/dist/components/tree/TreeRuler.js.map +1 -0
  85. package/dist/components/{TreePanel → tree}/dialogs/TreeNodeInfoDialog.js +6 -2
  86. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -0
  87. package/dist/components/{TreePanel → tree}/renderTreeCanvas.js +23 -37
  88. package/dist/components/tree/renderTreeCanvas.js.map +1 -0
  89. package/dist/fetchUtils.d.ts +5 -0
  90. package/dist/fetchUtils.js +23 -0
  91. package/dist/fetchUtils.js.map +1 -0
  92. package/dist/ggplotPalettes.d.ts +3 -0
  93. package/dist/ggplotPalettes.js +24 -0
  94. package/dist/ggplotPalettes.js.map +1 -0
  95. package/dist/index.d.ts +1 -1
  96. package/dist/index.js +1 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/launchInterProScan.d.ts +32 -0
  99. package/dist/launchInterProScan.js +47 -0
  100. package/dist/launchInterProScan.js.map +1 -0
  101. package/dist/model/DataModel.js.map +1 -0
  102. package/dist/model/DialogQueue.js.map +1 -0
  103. package/dist/model/msaModel.d.ts +14 -0
  104. package/dist/model/msaModel.js +36 -0
  105. package/dist/model/msaModel.js.map +1 -0
  106. package/dist/model/treeModel.d.ts +46 -0
  107. package/dist/model/treeModel.js +105 -0
  108. package/dist/model/treeModel.js.map +1 -0
  109. package/dist/model.d.ts +261 -273
  110. package/dist/model.js +1043 -1029
  111. package/dist/model.js.map +1 -1
  112. package/dist/parseGFF.d.ts +10 -0
  113. package/dist/parseGFF.js +29 -0
  114. package/dist/parseGFF.js.map +1 -0
  115. package/dist/renderToSvg.js +23 -9
  116. package/dist/renderToSvg.js.map +1 -1
  117. package/dist/reparseTree.d.ts +2 -0
  118. package/dist/reparseTree.js +13 -0
  119. package/dist/reparseTree.js.map +1 -0
  120. package/dist/util.d.ts +4 -10
  121. package/dist/util.js +3 -28
  122. package/dist/util.js.map +1 -1
  123. package/dist/version.d.ts +1 -1
  124. package/dist/version.js +1 -1
  125. package/package.json +12 -2
  126. package/src/components/Checkbox2.tsx +34 -0
  127. package/src/components/Loading.tsx +27 -11
  128. package/src/components/MSAView.tsx +6 -10
  129. package/src/components/SequenceTextArea.tsx +63 -0
  130. package/src/components/Track.tsx +8 -13
  131. package/src/components/dialogs/AddTrackDialog.tsx +0 -1
  132. package/src/components/{ExportSVGDialog.tsx → dialogs/ExportSVGDialog.tsx} +9 -16
  133. package/src/components/dialogs/FeatureDialog.tsx +109 -0
  134. package/src/components/dialogs/InterProScanDialog.tsx +230 -0
  135. package/src/components/dialogs/MetadataDialog.tsx +9 -2
  136. package/src/components/dialogs/SettingsDialog.tsx +10 -30
  137. package/src/components/header/Header.tsx +44 -0
  138. package/src/components/header/HeaderInfoArea.tsx +27 -0
  139. package/src/components/header/HeaderMenu.tsx +54 -0
  140. package/src/components/header/HeaderMenuExtra.tsx +108 -0
  141. package/src/components/header/HeaderStatusArea.tsx +31 -0
  142. package/src/components/{MultiAlignmentSelector.tsx → header/MultiAlignmentSelector.tsx} +1 -1
  143. package/src/components/header/ZoomControls.tsx +28 -0
  144. package/src/components/{ImportForm → import}/ImportFormExamples.tsx +12 -1
  145. package/src/components/{ImportForm → import}/util.ts +5 -10
  146. package/src/components/{Minimap.tsx → minimap/Minimap.tsx} +1 -1
  147. package/src/components/{MinimapSVG.tsx → minimap/MinimapSVG.tsx} +1 -1
  148. package/src/components/{MSAPanel → msa}/MSACanvas.tsx +3 -2
  149. package/src/components/{MSAPanel/MSABlock.tsx → msa/MSACanvasBlock.tsx} +25 -12
  150. package/src/components/{MSAPanel/index.tsx → msa/MSAPanel.tsx} +8 -2
  151. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +88 -0
  152. package/src/components/{MSAPanel → msa}/renderMSABlock.ts +26 -20
  153. package/src/components/{TreePanel → tree}/TreeCanvas.tsx +1 -1
  154. package/src/components/{TreePanel → tree}/TreeCanvasBlock.tsx +1 -1
  155. package/src/components/{TreePanel → tree}/TreeNodeMenu.tsx +1 -53
  156. package/src/components/{TreePanel/index.tsx → tree/TreePanel.tsx} +1 -1
  157. package/src/components/{TreePanel → tree}/dialogs/TreeNodeInfoDialog.tsx +9 -2
  158. package/src/components/{TreePanel → tree}/renderTreeCanvas.ts +25 -41
  159. package/src/fetchUtils.ts +30 -0
  160. package/src/ggplotPalettes.ts +25 -0
  161. package/src/index.ts +1 -1
  162. package/src/launchInterProScan.ts +98 -0
  163. package/src/model/msaModel.ts +39 -0
  164. package/src/model/treeModel.ts +116 -0
  165. package/src/model.ts +1124 -1126
  166. package/src/parseGFF.ts +32 -0
  167. package/src/renderToSvg.tsx +27 -8
  168. package/src/reparseTree.ts +16 -0
  169. package/src/util.ts +4 -33
  170. package/src/version.ts +1 -1
  171. package/dist/DataModel.js.map +0 -1
  172. package/dist/DialogQueue.js.map +0 -1
  173. package/dist/SelectedStructuresMixin.d.ts +0 -46
  174. package/dist/SelectedStructuresMixin.js +0 -52
  175. package/dist/SelectedStructuresMixin.js.map +0 -1
  176. package/dist/StructureModel.d.ts +0 -9
  177. package/dist/StructureModel.js +0 -11
  178. package/dist/StructureModel.js.map +0 -1
  179. package/dist/UniprotTrack.d.ts +0 -27
  180. package/dist/UniprotTrack.js +0 -53
  181. package/dist/UniprotTrack.js.map +0 -1
  182. package/dist/components/BoxTrack.d.ts +0 -7
  183. package/dist/components/BoxTrack.js +0 -15
  184. package/dist/components/BoxTrack.js.map +0 -1
  185. package/dist/components/BoxTrackBlock.d.ts +0 -8
  186. package/dist/components/BoxTrackBlock.js +0 -136
  187. package/dist/components/BoxTrackBlock.js.map +0 -1
  188. package/dist/components/ExportSVGDialog.js.map +0 -1
  189. package/dist/components/Header.js +0 -62
  190. package/dist/components/Header.js.map +0 -1
  191. package/dist/components/HeaderInfoArea.js +0 -12
  192. package/dist/components/HeaderInfoArea.js.map +0 -1
  193. package/dist/components/ImportForm/ImportFormExamples.js.map +0 -1
  194. package/dist/components/ImportForm/data/seq2.js.map +0 -1
  195. package/dist/components/ImportForm/index.js.map +0 -1
  196. package/dist/components/ImportForm/util.js +0 -16
  197. package/dist/components/ImportForm/util.js.map +0 -1
  198. package/dist/components/MSAPanel/Loading.js.map +0 -1
  199. package/dist/components/MSAPanel/MSABlock.js.map +0 -1
  200. package/dist/components/MSAPanel/MSACanvas.js.map +0 -1
  201. package/dist/components/MSAPanel/MSAMouseoverCanvas.js.map +0 -1
  202. package/dist/components/MSAPanel/index.d.ts +0 -5
  203. package/dist/components/MSAPanel/index.js.map +0 -1
  204. package/dist/components/MSAPanel/renderMSABlock.js.map +0 -1
  205. package/dist/components/MSAPanel/renderMSAMouseover.js.map +0 -1
  206. package/dist/components/Minimap.js.map +0 -1
  207. package/dist/components/MinimapSVG.js.map +0 -1
  208. package/dist/components/MultiAlignmentSelector.js.map +0 -1
  209. package/dist/components/TreePanel/TreeBranchMenu.js.map +0 -1
  210. package/dist/components/TreePanel/TreeCanvas.js.map +0 -1
  211. package/dist/components/TreePanel/TreeCanvasBlock.js.map +0 -1
  212. package/dist/components/TreePanel/TreeNodeMenu.js.map +0 -1
  213. package/dist/components/TreePanel/TreeRuler.js.map +0 -1
  214. package/dist/components/TreePanel/dialogs/TreeNodeInfoDialog.js.map +0 -1
  215. package/dist/components/TreePanel/index.js.map +0 -1
  216. package/dist/components/TreePanel/renderTreeCanvas.js.map +0 -1
  217. package/dist/components/VerticalGuide.d.ts +0 -7
  218. package/dist/components/VerticalGuide.js +0 -30
  219. package/dist/components/VerticalGuide.js.map +0 -1
  220. package/dist/components/ZoomControls.js +0 -59
  221. package/dist/components/ZoomControls.js.map +0 -1
  222. package/src/SelectedStructuresMixin.ts +0 -59
  223. package/src/StructureModel.ts +0 -11
  224. package/src/UniprotTrack.ts +0 -59
  225. package/src/components/BoxTrack.tsx +0 -33
  226. package/src/components/BoxTrackBlock.tsx +0 -200
  227. package/src/components/Header.tsx +0 -99
  228. package/src/components/HeaderInfoArea.tsx +0 -21
  229. package/src/components/VerticalGuide.tsx +0 -50
  230. package/src/components/ZoomControls.tsx +0 -86
  231. package/dist/components/{MultiAlignmentSelector.js → header/MultiAlignmentSelector.js} +0 -0
  232. package/dist/components/{ImportForm/index.d.ts → import/ImportForm.d.ts} +0 -0
  233. package/dist/components/{ImportForm → import}/ImportFormExamples.d.ts +0 -0
  234. package/dist/components/{ImportForm → import}/data/seq2.d.ts +0 -0
  235. package/dist/components/{ImportForm → import}/data/seq2.js +0 -0
  236. package/dist/components/{ImportForm → import}/util.d.ts +0 -0
  237. package/dist/components/{Minimap.js → minimap/Minimap.js} +0 -0
  238. package/dist/components/{MinimapSVG.js → minimap/MinimapSVG.js} +0 -0
  239. package/dist/components/{MSAPanel → msa}/Loading.d.ts +0 -0
  240. package/dist/components/{MSAPanel → msa}/Loading.js +0 -0
  241. package/dist/components/{MSAPanel → msa}/MSACanvas.d.ts +0 -0
  242. package/dist/components/{MSAPanel/MSABlock.d.ts → msa/MSACanvasBlock.d.ts} +0 -0
  243. package/dist/components/{MSAPanel → msa}/MSAMouseoverCanvas.d.ts +0 -0
  244. package/dist/components/{MSAPanel → msa}/MSAMouseoverCanvas.js +0 -0
  245. package/dist/components/{MSAPanel → msa}/renderMSABlock.d.ts +1 -1
  246. /package/dist/components/{MSAPanel → msa}/renderMSAMouseover.d.ts +0 -0
  247. /package/dist/components/{MSAPanel → msa}/renderMSAMouseover.js +0 -0
  248. /package/dist/components/{TreePanel → tree}/TreeBranchMenu.d.ts +0 -0
  249. /package/dist/components/{TreePanel → tree}/TreeBranchMenu.js +0 -0
  250. /package/dist/components/{TreePanel → tree}/TreeCanvas.d.ts +0 -0
  251. /package/dist/components/{TreePanel → tree}/TreeCanvasBlock.d.ts +0 -0
  252. /package/dist/components/{TreePanel → tree}/TreeNodeMenu.d.ts +0 -0
  253. /package/dist/components/{TreePanel/index.d.ts → tree/TreePanel.d.ts} +0 -0
  254. /package/dist/components/{TreePanel → tree}/TreeRuler.d.ts +0 -0
  255. /package/dist/components/{TreePanel → tree}/TreeRuler.js +0 -0
  256. /package/dist/components/{TreePanel → tree}/dialogs/TreeNodeInfoDialog.d.ts +0 -0
  257. /package/dist/components/{TreePanel → tree}/renderTreeCanvas.d.ts +0 -0
  258. /package/dist/{DataModel.d.ts → model/DataModel.d.ts} +0 -0
  259. /package/dist/{DataModel.js → model/DataModel.js} +0 -0
  260. /package/dist/{DialogQueue.d.ts → model/DialogQueue.d.ts} +0 -0
  261. /package/dist/{DialogQueue.js → model/DialogQueue.js} +0 -0
  262. /package/src/components/{ImportForm/index.tsx → import/ImportForm.tsx} +0 -0
  263. /package/src/components/{ImportForm → import}/data/seq2.ts +0 -0
  264. /package/src/components/{MSAPanel → msa}/Loading.tsx +0 -0
  265. /package/src/components/{MSAPanel → msa}/MSAMouseoverCanvas.tsx +0 -0
  266. /package/src/components/{MSAPanel → msa}/renderMSAMouseover.ts +0 -0
  267. /package/src/components/{TreePanel → tree}/TreeBranchMenu.tsx +0 -0
  268. /package/src/components/{TreePanel → tree}/TreeRuler.tsx +0 -0
  269. /package/src/{DataModel.ts → model/DataModel.ts} +0 -0
  270. /package/src/{DialogQueue.ts → model/DialogQueue.ts} +0 -0
package/dist/model.js CHANGED
@@ -1,4 +1,4 @@
1
- import { autorun } from 'mobx';
1
+ import { autorun, transaction } from 'mobx';
2
2
  import { cast, types, addDisposer } from 'mobx-state-tree';
3
3
  import { hierarchy, cluster } from 'd3-hierarchy';
4
4
  import { ascending } from 'd3-array';
@@ -7,15 +7,16 @@ import { saveAs } from 'file-saver';
7
7
  // jbrowse
8
8
  import { FileLocation, ElementId } from '@jbrowse/core/util/types/mst';
9
9
  import { openLocation } from '@jbrowse/core/util/io';
10
- import { notEmpty, sum } from '@jbrowse/core/util';
11
- import BaseViewModel from '@jbrowse/core/pluggableElementTypes/models/BaseViewModel';
10
+ import { groupBy, localStorageGetItem, localStorageSetItem, notEmpty, sum, } from '@jbrowse/core/util';
12
11
  // locals
13
- import { clamp, collapse, generateNodeIds, maxLength, setBrLength, skipBlanks, } from './util';
12
+ import { clamp, collapse, generateNodeIds, maxLength, setBrLength, skipBlanks, len, } from './util';
13
+ import { colord } from 'colord';
14
+ import { reparseTree } from './reparseTree';
14
15
  import { blocksX, blocksY } from './calculateBlocks';
15
16
  import { measureTextCanvas } from './measureTextCanvas';
17
+ import palettes from './ggplotPalettes';
16
18
  // components
17
19
  import TextTrack from './components/TextTrack';
18
- import BoxTrack from './components/BoxTrack';
19
20
  // parsers
20
21
  import ClustalMSA from './parsers/ClustalMSA';
21
22
  import StockholmMSA from './parsers/StockholmMSA';
@@ -23,1069 +24,1082 @@ import FastaMSA from './parsers/FastaMSA';
23
24
  import parseNewick from './parseNewick';
24
25
  import colorSchemes from './colorSchemes';
25
26
  // models
26
- import { UniprotTrack } from './UniprotTrack';
27
- import { DataModelF } from './DataModel';
28
- import { DialogQueueSessionMixin } from './DialogQueue';
29
- import { SelectedStructuresMixin } from './SelectedStructuresMixin';
27
+ import { DataModelF } from './model/DataModel';
28
+ import { DialogQueueSessionMixin } from './model/DialogQueue';
29
+ import { TreeF } from './model/treeModel';
30
+ import { MSAModelF } from './model/msaModel';
31
+ import { launchInterProScan, loadInterProScanResults, } from './launchInterProScan';
30
32
  /**
31
33
  * #stateModel MsaView
32
34
  * extends
33
- * - BaseViewModel
34
35
  * - DialogQueueSessionMixin
35
- * - SelectedStructuresMixin
36
+ * - MSAModel
37
+ * - Tree
36
38
  */
37
- function x() { } // eslint-disable-line @typescript-eslint/no-unused-vars
38
- function reparseTree(tree) {
39
- return {
40
- ...tree,
41
- branchset: tree.branchset.map(r => r.branchset.length
42
- ? reparseTree(r)
43
- : {
44
- branchset: [r],
45
- id: `${r.id}-leafnode`,
46
- name: `${r.name}-hidden`,
47
- }),
48
- };
49
- }
50
- const model = types
51
- .compose(BaseViewModel, DialogQueueSessionMixin(), SelectedStructuresMixin(), types.model('MsaView', {
52
- /**
53
- * #property
54
- * id of view, randomly generated if not provided
55
- */
56
- id: ElementId,
57
- /**
58
- * #property
59
- * hardcoded view type
60
- */
61
- type: types.literal('MsaView'),
62
- /**
63
- * #property
64
- * height of the div containing the view, px
65
- */
66
- height: types.optional(types.number, 550),
67
- /**
68
- * #property
69
- * width of the area the tree is drawn in, px
70
- */
71
- treeAreaWidth: types.optional(types.number, 400),
72
- /**
73
- * #property
74
- * width of the tree within the treeArea, px
75
- */
76
- treeWidth: types.optional(types.number, 300),
77
- /**
78
- * #getter
79
- * synchronization that matches treeWidth to treeAreaWidth
80
- */
81
- treeWidthMatchesArea: true,
82
- /**
83
- * #property
84
- * height of each row, px
85
- */
86
- rowHeight: 20,
87
- /**
88
- * #property
89
- * scroll position, Y-offset, px
90
- */
91
- scrollY: 0,
92
- /**
93
- * #property
94
- * scroll position, X-offset, px
95
- */
96
- scrollX: 0,
97
- /**
98
- * #property
99
- * right-align the labels
100
- */
101
- labelsAlignRight: false,
102
- /**
103
- * #property
104
- * width of columns, px
105
- */
106
- colWidth: 16,
107
- /**
108
- * #property
109
- * use "branch length" e.g. evolutionary distance to draw tree branch
110
- * lengths. if false, the layout is a "cladogram" that does not take into
111
- * account evolutionary distances
112
- */
113
- showBranchLen: true,
114
- /**
115
- * #property
116
- * draw MSA tiles with a background color
117
- */
118
- bgColor: true,
119
- /**
120
- * #property
121
- * draw tree, boolean
122
- */
123
- drawTree: true,
124
- /**
125
- * #property
126
- * draw clickable node bubbles on the tree
127
- */
128
- drawNodeBubbles: true,
129
- /**
130
- * #property
131
- * high resolution scale factor, helps make canvas look better on hi-dpi
132
- * screens
133
- */
134
- highResScaleFactor: 2,
135
- /**
136
- * #property
137
- * default color scheme name
138
- */
139
- colorSchemeName: 'maeditor',
140
- /**
141
- * #property
142
- * filehandle object for the tree
143
- */
144
- treeFilehandle: types.maybe(FileLocation),
145
- /**
146
- * #property
147
- * filehandle object for the MSA (which could contain a tree e.g. with
148
- * stockholm files)
149
- */
150
- msaFilehandle: types.maybe(FileLocation),
151
- /**
152
- * #property
153
- * filehandle object for tree metadata
154
- */
155
- treeMetadataFilehandle: types.maybe(FileLocation),
156
- /**
157
- * #property
158
- *
159
- */
160
- currentAlignment: 0,
161
- /**
162
- * #property
163
- * array of tree nodes that are 'collapsed'
164
- */
165
- collapsed: types.array(types.string),
166
- collapsed2: types.array(types.string),
167
- /**
168
- * #property
169
- * focus on particular subtree
170
- */
171
- showOnly: types.maybe(types.string),
172
- /**
173
- * #property
174
- * a list of "tracks" to display, as box-like glyphs (e.g. protein
175
- * domains)
176
- */
177
- boxTracks: types.array(UniprotTrack),
178
- /**
179
- * #property
180
- * turned off tracks
181
- */
182
- turnedOffTracks: types.map(types.boolean),
183
- /**
184
- * #property
185
- * data from the loaded tree/msa/treeMetadata, generally loaded by
186
- * autorun
187
- */
188
- data: types.optional(DataModelF(), { tree: '', msa: '' }),
189
- }))
190
- .volatile(() => ({
191
- /**
192
- * #volatile
193
- * resize handle width between tree and msa area, px
194
- */
195
- resizeHandleWidth: 5,
196
- /**
197
- * #volatile
198
- * size of blocks of content to be drawn, px
199
- */
200
- blockSize: 1000,
201
- /**
202
- * #volatile
203
- * the currently mouse-hovered row
204
- */
205
- mouseRow: undefined,
206
- /**
207
- * #volatile
208
- * the currently mouse-hovered column
209
- */
210
- mouseCol: undefined,
211
- /**
212
- * #volatile
213
- * the currently mouse-click row
214
- */
215
- mouseClickRow: undefined,
216
- /**
217
- * #volatile
218
- * the currently mouse-click column
219
- */
220
- mouseClickCol: undefined,
221
- /**
222
- * #volatile
223
- * a dummy variable that is incremented when ref changes so autorun for
224
- * drawing canvas commands will run
225
- */
226
- nref: 0,
227
- /**
228
- * #volatile
229
- */
230
- minimapHeight: 56,
231
- /**
232
- * #volatile
233
- */
234
- marginLeft: 20,
235
- /**
236
- * #volatile
237
- */
238
- error: undefined,
239
- /**
240
- * #volatile
241
- */
242
- annotPos: undefined,
243
- }))
244
- .actions(self => ({
245
- /**
246
- * #action
247
- * set the height of the view in px
248
- */
249
- setHeight(height) {
250
- self.height = height;
251
- },
252
- /**
253
- * #action
254
- * set error state
255
- */
256
- setError(error) {
257
- self.error = error;
258
- },
259
- /**
260
- * #action
261
- * set mouse position (row, column) in the MSA
262
- */
263
- setMousePos(col, row) {
264
- self.mouseCol = col;
265
- self.mouseRow = row;
266
- },
267
- /**
268
- * #action
269
- * set mouse click position (row, column) in the MSA
270
- */
271
- setMouseClickPos(col, row) {
272
- self.mouseClickCol = col;
273
- self.mouseClickRow = row;
274
- },
275
- /**
276
- * #action
277
- * set row height (px)
278
- */
279
- setRowHeight(n) {
280
- self.rowHeight = n;
281
- },
282
- /**
283
- * #action
284
- * set col width (px)
285
- */
286
- setColWidth(n) {
287
- self.colWidth = n;
288
- },
289
- /**
290
- * #action
291
- * set color scheme name
292
- */
293
- setColorSchemeName(name) {
294
- self.colorSchemeName = name;
295
- },
296
- /**
297
- * #action
298
- * synchronize the treewidth and treeareawidth
299
- */
300
- setTreeWidthMatchesArea(arg) {
301
- self.treeWidthMatchesArea = arg;
302
- },
303
- /**
304
- * #action
305
- * set scroll Y-offset (px)
306
- */
307
- setScrollY(n) {
308
- self.scrollY = n;
309
- },
310
- /**
311
- * #action
312
- * set tree area width (px)
313
- */
314
- setTreeAreaWidth(n) {
315
- self.treeAreaWidth = n;
316
- },
317
- /**
318
- * #action
319
- * set tree width (px)
320
- */
321
- setTreeWidth(n) {
322
- self.treeWidth = n;
323
- },
324
- /**
325
- * #action
326
- *
327
- */
328
- setCurrentAlignment(n) {
329
- self.currentAlignment = n;
330
- },
331
- /**
332
- * #action
333
- */
334
- setLabelsAlignRight(arg) {
335
- self.labelsAlignRight = arg;
336
- },
337
- /**
338
- * #action
339
- */
340
- setDrawTree(arg) {
341
- self.drawTree = arg;
342
- },
343
- /**
344
- * #action
345
- */
346
- toggleCollapsed(node) {
347
- if (self.collapsed.includes(node)) {
348
- self.collapsed.remove(node);
349
- }
350
- else {
351
- self.collapsed.push(node);
352
- }
353
- },
354
- /**
355
- * #action
356
- */
357
- toggleCollapsed2(node) {
358
- if (self.collapsed2.includes(node)) {
359
- self.collapsed2.remove(node);
360
- }
361
- else {
362
- self.collapsed2.push(node);
363
- }
364
- },
365
- /**
366
- * #action
367
- */
368
- setShowOnly(node) {
369
- self.showOnly = node;
370
- },
371
- /**
372
- * #action
373
- */
374
- setShowBranchLen(arg) {
375
- self.showBranchLen = arg;
376
- },
377
- /**
378
- * #action
379
- */
380
- setBgColor(arg) {
381
- self.bgColor = arg;
382
- },
383
- /**
384
- * #action
385
- */
386
- setDrawNodeBubbles(arg) {
387
- self.drawNodeBubbles = arg;
388
- },
389
- /**
390
- * #action
391
- */
392
- setData(data) {
393
- self.data = cast(data);
394
- },
395
- /**
396
- * #action
397
- */
398
- async setMSAFilehandle(msaFilehandle) {
399
- self.msaFilehandle = msaFilehandle;
400
- },
401
- /**
402
- * #action
403
- */
404
- async setTreeFilehandle(treeFilehandle) {
405
- if (treeFilehandle && 'blobId' in treeFilehandle) {
406
- const r = await openLocation(treeFilehandle).readFile('utf8');
407
- this.setTree(r);
408
- }
409
- else {
410
- self.treeFilehandle = treeFilehandle;
411
- }
412
- },
413
- /**
414
- * #action
415
- */
416
- setMSA(result) {
417
- self.data.setMSA(result);
418
- },
419
- /**
420
- * #action
421
- */
422
- setTree(result) {
423
- self.data.setTree(result);
424
- },
425
- /**
426
- * #action
427
- */
428
- setTreeMetadata(result) {
429
- self.data.setTreeMetadata(result);
430
- },
431
- }))
432
- .views(self => ({
433
- /**
434
- * #getter
435
- */
436
- get colorScheme() {
437
- return colorSchemes[self.colorSchemeName];
438
- },
439
- /**
440
- * #getter
441
- */
442
- get header() {
443
- return this.MSA?.getHeader() || {};
444
- },
445
- /**
446
- * #method
447
- */
448
- getRowData(name) {
449
- const matches = name.match(/\S+\/(\d+)-(\d+)/);
450
- return {
451
- data: this.MSA?.getRowData(name) || {},
452
- ...(matches && {
453
- range: {
454
- start: +matches[1],
455
- end: +matches[2],
456
- },
457
- }),
458
- };
459
- },
460
- /**
461
- * #getter
462
- */
463
- get currentAlignmentName() {
464
- return this.alignmentNames[self.currentAlignment];
465
- },
466
- /**
467
- * #getter
468
- */
469
- get alignmentNames() {
470
- return this.MSA?.alignmentNames || [];
471
- },
472
- /**
473
- * #getter
474
- */
475
- get noTree() {
476
- return !!this._tree.noTree;
477
- },
478
- /**
479
- * #getter
480
- */
481
- get menuItems() {
482
- return [];
483
- },
484
- /**
485
- * #getter
486
- */
487
- get treeMetadata() {
488
- return self.data.treeMetadata ? JSON.parse(self.data.treeMetadata) : {};
489
- },
490
- /**
491
- * #getter
492
- */
493
- get MSA() {
494
- const text = self.data.msa;
495
- if (text) {
496
- if (Stockholm.sniff(text)) {
497
- return new StockholmMSA(text, self.currentAlignment);
39
+ function stateModelFactory() {
40
+ return types
41
+ .compose(DialogQueueSessionMixin(), TreeF(), MSAModelF(), types.model('MsaView', {
42
+ /**
43
+ * #property
44
+ * id of view, randomly generated if not provided
45
+ */
46
+ id: ElementId,
47
+ /**
48
+ * #property
49
+ */
50
+ featureMode: false,
51
+ /**
52
+ * #property
53
+ */
54
+ subFeatureRows: false,
55
+ /**
56
+ * #property
57
+ * hardcoded view type
58
+ */
59
+ type: types.literal('MsaView'),
60
+ /**
61
+ * #property
62
+ * height of the div containing the view, px
63
+ */
64
+ height: types.optional(types.number, 550),
65
+ /**
66
+ * #property
67
+ * height of each row, px
68
+ */
69
+ rowHeight: 20,
70
+ /**
71
+ * #property
72
+ * scroll position, Y-offset, px
73
+ */
74
+ scrollY: 0,
75
+ /**
76
+ * #property
77
+ * scroll position, X-offset, px
78
+ */
79
+ scrollX: 0,
80
+ /**
81
+ * #property
82
+ * width of columns, px
83
+ */
84
+ colWidth: 16,
85
+ /**
86
+ * #property
87
+ * filehandle object for the tree
88
+ */
89
+ treeFilehandle: types.maybe(FileLocation),
90
+ /**
91
+ * #property
92
+ * filehandle object for the MSA (which could contain a tree e.g. with
93
+ * stockholm files)
94
+ */
95
+ msaFilehandle: types.maybe(FileLocation),
96
+ /**
97
+ * #property
98
+ * filehandle object for tree metadata
99
+ */
100
+ treeMetadataFilehandle: types.maybe(FileLocation),
101
+ /**
102
+ * #property
103
+ *
104
+ */
105
+ currentAlignment: 0,
106
+ /**
107
+ * #property
108
+ * array of tree parent nodes that are 'collapsed'
109
+ */
110
+ collapsed: types.array(types.string),
111
+ /**
112
+ * #property
113
+ * array of tree leaf nodes that are 'collapsed'
114
+ */
115
+ collapsed2: types.array(types.string),
116
+ /**
117
+ * #property
118
+ * focus on particular subtree
119
+ */
120
+ showOnly: types.maybe(types.string),
121
+ /**
122
+ * #property
123
+ * turned off tracks
124
+ */
125
+ turnedOffTracks: types.map(types.boolean),
126
+ /**
127
+ * #property
128
+ * data from the loaded tree/msa/treeMetadata, generally loaded by
129
+ * autorun
130
+ */
131
+ data: types.optional(DataModelF(), { tree: '', msa: '' }),
132
+ /**
133
+ * #property
134
+ */
135
+ featureFilters: types.map(types.boolean),
136
+ }))
137
+ .volatile(() => ({
138
+ status: undefined,
139
+ /**
140
+ * #volatile
141
+ * high resolution scale factor, helps make canvas look better on hi-dpi
142
+ * screens
143
+ */
144
+ highResScaleFactor: 1,
145
+ /**
146
+ * #volatile
147
+ */
148
+ loadingMSA: false,
149
+ /**
150
+ * #volatile
151
+ */
152
+ loadingTree: false,
153
+ /**
154
+ * #volatile
155
+ */
156
+ width: 800,
157
+ /**
158
+ * #volatile
159
+ * resize handle width between tree and msa area, px
160
+ */
161
+ resizeHandleWidth: 5,
162
+ /**
163
+ * #volatile
164
+ * size of blocks of content to be drawn, px
165
+ */
166
+ blockSize: 1000,
167
+ /**
168
+ * #volatile
169
+ * the currently mouse-hovered row
170
+ */
171
+ mouseRow: undefined,
172
+ /**
173
+ * #volatile
174
+ * the currently mouse-hovered column
175
+ */
176
+ mouseCol: undefined,
177
+ /**
178
+ * #volatile
179
+ * the currently mouse-click row
180
+ */
181
+ mouseClickRow: undefined,
182
+ /**
183
+ * #volatile
184
+ * the currently mouse-click column
185
+ */
186
+ mouseClickCol: undefined,
187
+ /**
188
+ * #volatile
189
+ * a dummy variable that is incremented when ref changes so autorun for
190
+ * drawing canvas commands will run
191
+ */
192
+ nref: 0,
193
+ /**
194
+ * #volatile
195
+ */
196
+ minimapHeight: 56,
197
+ /**
198
+ * #volatile
199
+ */
200
+ marginLeft: 20,
201
+ /**
202
+ * #volatile
203
+ */
204
+ error: undefined,
205
+ /**
206
+ * #volatile
207
+ */
208
+ annotPos: undefined,
209
+ /**
210
+ * #volatile
211
+ *
212
+ */
213
+ loadedInterProAnnotations: undefined,
214
+ /**
215
+ * #volatile
216
+ */
217
+ interProScanJobIds: JSON.parse(localStorageGetItem('msaview-interproscanqueries') || '[]'),
218
+ }))
219
+ .actions(self => ({
220
+ /**
221
+ * #action
222
+ */
223
+ setLoadingMSA(arg) {
224
+ self.loadingMSA = arg;
225
+ },
226
+ /**
227
+ * #action
228
+ */
229
+ setLoadingTree(arg) {
230
+ self.loadingTree = arg;
231
+ },
232
+ /**
233
+ * #action
234
+ */
235
+ setWidth(arg) {
236
+ self.width = arg;
237
+ },
238
+ /**
239
+ * #action
240
+ * set the height of the view in px
241
+ */
242
+ setHeight(height) {
243
+ self.height = height;
244
+ },
245
+ /**
246
+ * #action
247
+ * set error state
248
+ */
249
+ setError(error) {
250
+ self.error = error;
251
+ },
252
+ /**
253
+ * #action
254
+ * set mouse position (row, column) in the MSA
255
+ */
256
+ setMousePos(col, row) {
257
+ self.mouseCol = col;
258
+ self.mouseRow = row;
259
+ },
260
+ /**
261
+ * #action
262
+ */
263
+ setFeatureMode(arg) {
264
+ self.featureMode = arg;
265
+ },
266
+ /**
267
+ * #action
268
+ */
269
+ setSubFeatureRows(arg) {
270
+ self.subFeatureRows = arg;
271
+ },
272
+ /**
273
+ * #action
274
+ * set mouse click position (row, column) in the MSA
275
+ */
276
+ setMouseClickPos(col, row) {
277
+ self.mouseClickCol = col;
278
+ self.mouseClickRow = row;
279
+ },
280
+ /**
281
+ * #action
282
+ * set row height (px)
283
+ */
284
+ setRowHeight(n) {
285
+ self.rowHeight = n;
286
+ },
287
+ /**
288
+ * #action
289
+ * set col width (px)
290
+ */
291
+ setColWidth(n) {
292
+ self.colWidth = n;
293
+ },
294
+ /**
295
+ * #action
296
+ * set scroll Y-offset (px)
297
+ */
298
+ setScrollY(n) {
299
+ self.scrollY = n;
300
+ },
301
+ /**
302
+ * #action
303
+ *
304
+ */
305
+ setCurrentAlignment(n) {
306
+ self.currentAlignment = n;
307
+ },
308
+ /**
309
+ * #action
310
+ */
311
+ toggleCollapsed(node) {
312
+ if (self.collapsed.includes(node)) {
313
+ self.collapsed.remove(node);
314
+ }
315
+ else {
316
+ self.collapsed.push(node);
498
317
  }
499
- else if (text.startsWith('>')) {
500
- return new FastaMSA(text);
318
+ },
319
+ /**
320
+ * #action
321
+ */
322
+ toggleCollapsed2(node) {
323
+ if (self.collapsed2.includes(node)) {
324
+ self.collapsed2.remove(node);
501
325
  }
502
326
  else {
503
- return new ClustalMSA(text);
327
+ self.collapsed2.push(node);
504
328
  }
505
- }
506
- return null;
507
- },
508
- /**
509
- * #getter
510
- */
511
- get numColumns() {
512
- return (this.MSA?.getWidth() || 0) - this.blanks.length;
513
- },
514
- /**
515
- * #getter
516
- */
517
- get _tree() {
518
- const ret = self.data.tree
519
- ? generateNodeIds(parseNewick(self.data.tree))
520
- : this.MSA?.getTree() || {
521
- noTree: true,
522
- branchset: [],
523
- id: 'empty',
524
- name: 'empty',
329
+ },
330
+ /**
331
+ * #action
332
+ */
333
+ setShowOnly(node) {
334
+ self.showOnly = node;
335
+ },
336
+ /**
337
+ * #action
338
+ */
339
+ setData(data) {
340
+ self.data = cast(data);
341
+ },
342
+ /**
343
+ * #action
344
+ */
345
+ setMSAFilehandle(msaFilehandle) {
346
+ self.msaFilehandle = msaFilehandle;
347
+ },
348
+ /**
349
+ * #action
350
+ */
351
+ setTreeFilehandle(treeFilehandle) {
352
+ self.treeFilehandle = treeFilehandle;
353
+ },
354
+ /**
355
+ * #action
356
+ */
357
+ setMSA(result) {
358
+ self.data.setMSA(result);
359
+ },
360
+ /**
361
+ * #action
362
+ */
363
+ setTree(result) {
364
+ self.data.setTree(result);
365
+ },
366
+ /**
367
+ * #action
368
+ */
369
+ setTreeMetadata(result) {
370
+ self.data.setTreeMetadata(result);
371
+ },
372
+ }))
373
+ .views(self => ({
374
+ /**
375
+ * #method
376
+ * unused here, but can be used by derived classes to add extra items
377
+ */
378
+ extraViewMenuItems() {
379
+ return [];
380
+ },
381
+ /**
382
+ * #getter
383
+ */
384
+ get colorScheme() {
385
+ return colorSchemes[self.colorSchemeName];
386
+ },
387
+ /**
388
+ * #getter
389
+ */
390
+ get header() {
391
+ return this.MSA?.getHeader() || {};
392
+ },
393
+ /**
394
+ * #method
395
+ */
396
+ getRowData(name) {
397
+ return {
398
+ data: this.MSA?.getRowData(name),
525
399
  };
526
- return reparseTree(ret);
527
- },
528
- /**
529
- * #getter
530
- */
531
- get rowNames() {
532
- return this.hierarchy.leaves().map(node => node.data.name);
533
- },
534
- /**
535
- * #getter
536
- */
537
- get mouseOverRowName() {
538
- return self.mouseRow !== undefined
539
- ? this.rowNames[self.mouseRow]
540
- : undefined;
541
- },
542
- /**
543
- * #method
544
- */
545
- getMouseOverResidue(rowName) {
546
- return this.columns[rowName];
547
- },
548
- /**
549
- * #getter
550
- */
551
- get root() {
552
- let hier = hierarchy(this._tree, d => d.branchset)
553
- .sum(d => (d.branchset ? 0 : 1))
554
- .sort((a, b) => ascending(a.data.length || 1, b.data.length || 1));
555
- if (self.showOnly) {
556
- const res = hier.find(node => node.data.id === self.showOnly);
557
- if (res) {
558
- hier = res;
400
+ },
401
+ /**
402
+ * #getter
403
+ */
404
+ get alignmentNames() {
405
+ return this.MSA?.alignmentNames || [];
406
+ },
407
+ /**
408
+ * #getter
409
+ */
410
+ get noTree() {
411
+ return !!this._tree.noTree;
412
+ },
413
+ /**
414
+ * #getter
415
+ */
416
+ get noAnnotations() {
417
+ return !self.loadedInterProAnnotations;
418
+ },
419
+ /**
420
+ * #getter
421
+ */
422
+ get menuItems() {
423
+ return [];
424
+ },
425
+ /**
426
+ * #getter
427
+ */
428
+ get treeMetadata() {
429
+ return self.data.treeMetadata ? JSON.parse(self.data.treeMetadata) : {};
430
+ },
431
+ /**
432
+ * #getter
433
+ */
434
+ get MSA() {
435
+ const text = self.data.msa;
436
+ if (text) {
437
+ if (Stockholm.sniff(text)) {
438
+ return new StockholmMSA(text, self.currentAlignment);
439
+ }
440
+ else if (text.startsWith('>')) {
441
+ return new FastaMSA(text);
442
+ }
443
+ else {
444
+ return new ClustalMSA(text);
445
+ }
446
+ }
447
+ return null;
448
+ },
449
+ /**
450
+ * #getter
451
+ */
452
+ get numColumns() {
453
+ return (this.MSA?.getWidth() || 0) - this.blanks.length;
454
+ },
455
+ /**
456
+ * #getter
457
+ */
458
+ get _tree() {
459
+ const ret = self.data.tree
460
+ ? generateNodeIds(parseNewick(self.data.tree))
461
+ : this.MSA?.getTree() || {
462
+ noTree: true,
463
+ branchset: [],
464
+ id: 'empty',
465
+ name: 'empty',
466
+ };
467
+ return reparseTree(ret);
468
+ },
469
+ /**
470
+ * #getter
471
+ */
472
+ get rowNames() {
473
+ return this.hierarchy.leaves().map(n => n.data.name);
474
+ },
475
+ /**
476
+ * #getter
477
+ */
478
+ get mouseOverRowName() {
479
+ const { mouseRow } = self;
480
+ return mouseRow !== undefined ? this.rowNames[mouseRow] : undefined;
481
+ },
482
+ /**
483
+ * #getter
484
+ */
485
+ get root() {
486
+ let hier = hierarchy(this._tree, d => d.branchset)
487
+ .sum(d => (d.branchset ? 0 : 1))
488
+ .sort((a, b) => ascending(a.data.length || 1, b.data.length || 1));
489
+ if (self.showOnly) {
490
+ const res = hier.find(n => n.data.id === self.showOnly);
491
+ if (res) {
492
+ hier = res;
493
+ }
559
494
  }
560
- }
561
- if (self.collapsed.length || self.collapsed2.length) {
562
495
  ;
563
496
  [...self.collapsed, ...self.collapsed2]
564
497
  .map(collapsedId => hier.find(node => node.data.id === collapsedId))
565
498
  .filter(notEmpty)
566
499
  .map(node => collapse(node));
567
- }
568
- return hier;
569
- },
570
- /**
571
- * #getter
572
- */
573
- get structures() {
574
- return this.MSA?.getStructures() || {};
575
- },
576
- /**
577
- * #getter
578
- */
579
- get inverseStructures() {
580
- return Object.fromEntries(Object.entries(this.structures).flatMap(([key, val]) => val.map(pdbEntry => [pdbEntry.pdb, { id: key }])));
581
- },
582
- /**
583
- * #getter
584
- * widget width minus the tree area gives the space for the MSA
585
- */
586
- get msaAreaWidth() {
587
- return self.width - self.treeAreaWidth;
588
- },
589
- /**
590
- * #getter
591
- */
592
- get treeAreaWidthMinusMargin() {
593
- return self.treeAreaWidth - self.marginLeft;
594
- },
595
- /**
596
- * #getter
597
- */
598
- get blanks() {
599
- const blanks = [];
600
- const strs = this.hierarchy
601
- .leaves()
602
- .map(leaf => this.MSA?.getRow(leaf.data.name))
603
- .filter((item) => !!item);
604
- for (let i = 0; i < strs[0]?.length; i++) {
605
- let counter = 0;
606
- for (const str of strs) {
607
- if (str[i] === '-') {
608
- counter++;
500
+ return hier;
501
+ },
502
+ /**
503
+ * #getter
504
+ * widget width minus the tree area gives the space for the MSA
505
+ */
506
+ get msaAreaWidth() {
507
+ return self.width - self.treeAreaWidth;
508
+ },
509
+ /**
510
+ * #getter
511
+ */
512
+ get treeAreaWidthMinusMargin() {
513
+ return self.treeAreaWidth - self.marginLeft;
514
+ },
515
+ /**
516
+ * #getter
517
+ */
518
+ get blanks() {
519
+ const blanks = [];
520
+ const strs = this.hierarchy
521
+ .leaves()
522
+ .map(leaf => this.MSA?.getRow(leaf.data.name))
523
+ .filter((item) => !!item);
524
+ for (let i = 0; i < strs[0]?.length; i++) {
525
+ let counter = 0;
526
+ for (const str of strs) {
527
+ if (str[i] === '-') {
528
+ counter++;
529
+ }
530
+ }
531
+ if (counter === strs.length) {
532
+ blanks.push(i);
609
533
  }
610
534
  }
611
- if (counter === strs.length) {
612
- blanks.push(i);
535
+ return blanks;
536
+ },
537
+ /**
538
+ * #getter
539
+ */
540
+ get rows() {
541
+ const MSA = this.MSA;
542
+ return this.hierarchy
543
+ .leaves()
544
+ .map(leaf => [leaf.data.name, MSA?.getRow(leaf.data.name)])
545
+ .filter((f) => !!f[1]);
546
+ },
547
+ /**
548
+ * #getter
549
+ */
550
+ get columns() {
551
+ return Object.fromEntries(this.rows.map((row, index) => [row[0], this.columns2d[index]]));
552
+ },
553
+ /**
554
+ * #getter
555
+ */
556
+ get columns2d() {
557
+ return this.rows.map(r => r[1]).map(str => skipBlanks(this.blanks, str));
558
+ },
559
+ /**
560
+ * #getter
561
+ */
562
+ get fontSize() {
563
+ return Math.min(Math.max(6, self.rowHeight - 8), 18);
564
+ },
565
+ /**
566
+ * #getter
567
+ */
568
+ get colStats() {
569
+ const r = [];
570
+ const columns = this.columns2d;
571
+ for (const column of columns) {
572
+ for (let j = 0; j < column.length; j++) {
573
+ const l = r[j] || {};
574
+ if (!l[column[j]]) {
575
+ l[column[j]] = 0;
576
+ }
577
+ l[column[j]]++;
578
+ r[j] = l;
579
+ }
613
580
  }
614
- }
615
- return blanks;
616
- },
617
- /**
618
- * #getter
619
- */
620
- get rows() {
621
- const MSA = this.MSA;
622
- return this.hierarchy
623
- .leaves()
624
- .map(leaf => [leaf.data.name, MSA?.getRow(leaf.data.name)])
625
- .filter((f) => !!f[1]);
626
- },
627
- /**
628
- * #getter
629
- */
630
- get columns() {
631
- return Object.fromEntries(this.rows.map((row, index) => [row[0], this.columns2d[index]]));
632
- },
633
- /**
634
- * #getter
635
- */
636
- get columns2d() {
637
- return this.rows.map(r => r[1]).map(str => skipBlanks(this.blanks, str));
638
- },
639
- /**
640
- * #getter
641
- */
642
- get fontSize() {
643
- return Math.max(8, self.rowHeight - 8);
644
- },
645
- /**
646
- * #getter
647
- */
648
- get colStats() {
649
- const r = [];
650
- const columns = this.columns2d;
651
- for (const column of columns) {
652
- for (let j = 0; j < column.length; j++) {
653
- const l = r[j] || {};
654
- if (!l[column[j]]) {
655
- l[column[j]] = 0;
581
+ return r;
582
+ },
583
+ /**
584
+ * #getter
585
+ * generates a new tree that is clustered with x,y positions
586
+ */
587
+ get hierarchy() {
588
+ const r = this.root;
589
+ const clust = cluster()
590
+ .size([this.totalHeight, self.treeWidth])
591
+ .separation(() => 1);
592
+ clust(r);
593
+ setBrLength(r, (r.data.length = 0), self.treeWidth / maxLength(r));
594
+ return r;
595
+ },
596
+ /**
597
+ * #getter
598
+ */
599
+ get totalHeight() {
600
+ return this.root.leaves().length * self.rowHeight;
601
+ },
602
+ }))
603
+ .views(self => ({
604
+ /**
605
+ * #getter
606
+ */
607
+ get totalWidth() {
608
+ return self.numColumns * self.colWidth;
609
+ },
610
+ }))
611
+ .views(self => ({
612
+ /**
613
+ * #getter
614
+ */
615
+ get initialized() {
616
+ return (self.data.msa || self.data.tree) && !self.error;
617
+ },
618
+ /**
619
+ * #getter
620
+ */
621
+ get blocksX() {
622
+ return blocksX({
623
+ viewportWidth: self.msaAreaWidth,
624
+ viewportX: -self.scrollX,
625
+ blockSize: self.blockSize,
626
+ mapWidth: self.totalWidth,
627
+ });
628
+ },
629
+ /**
630
+ * #getter
631
+ */
632
+ get blocksY() {
633
+ return blocksY({
634
+ viewportHeight: self.height,
635
+ viewportY: -self.scrollY,
636
+ blockSize: self.blockSize,
637
+ mapHeight: self.totalHeight,
638
+ });
639
+ },
640
+ }))
641
+ .views(self => ({
642
+ /**
643
+ * #getter
644
+ */
645
+ get blocks2d() {
646
+ const ret = [];
647
+ for (const by of self.blocksY) {
648
+ for (const bx of self.blocksX) {
649
+ ret.push([bx, by]);
656
650
  }
657
- l[column[j]]++;
658
- r[j] = l;
659
651
  }
660
- }
661
- return r;
662
- },
663
- /**
664
- * #getter
665
- * generates a new tree that is clustered with x,y positions
666
- */
667
- get hierarchy() {
668
- const r = this.root;
669
- const clust = cluster()
670
- .size([this.totalHeight, self.treeWidth])
671
- .separation(() => 1);
672
- clust(r);
673
- setBrLength(r, (r.data.length = 0), self.treeWidth / maxLength(r));
674
- return r;
675
- },
676
- /**
677
- * #getter
678
- */
679
- get totalHeight() {
680
- return this.root.leaves().length * self.rowHeight;
681
- },
682
- }))
683
- .views(self => ({
684
- /**
685
- * #getter
686
- */
687
- get totalWidth() {
688
- return self.numColumns * self.colWidth;
689
- },
690
- }))
691
- .views(self => ({
692
- /**
693
- * #getter
694
- */
695
- get initialized() {
696
- return ((self.data.msa ||
697
- self.data.tree ||
698
- self.msaFilehandle ||
699
- self.treeFilehandle) &&
700
- !self.error);
701
- },
702
- /**
703
- * #getter
704
- */
705
- get blocksX() {
706
- return blocksX({
707
- viewportWidth: self.msaAreaWidth,
708
- viewportX: -self.scrollX,
709
- blockSize: self.blockSize,
710
- mapWidth: self.totalWidth,
711
- });
712
- },
713
- /**
714
- * #getter
715
- */
716
- get blocksY() {
717
- return blocksY({
718
- viewportHeight: self.height,
719
- viewportY: -self.scrollY,
720
- blockSize: self.blockSize,
721
- mapHeight: self.totalHeight,
722
- });
723
- },
724
- }))
725
- .views(self => ({
726
- /**
727
- * #getter
728
- */
729
- get blocks2d() {
730
- const ret = [];
731
- for (const by of self.blocksY) {
732
- for (const bx of self.blocksX) {
733
- ret.push([bx, by]);
652
+ return ret;
653
+ },
654
+ /**
655
+ * #getter
656
+ */
657
+ get isLoading() {
658
+ return self.loadingMSA || self.loadingTree;
659
+ },
660
+ /**
661
+ * #getter
662
+ */
663
+ get maxScrollX() {
664
+ return -self.totalWidth + (self.msaAreaWidth - 100);
665
+ },
666
+ }))
667
+ .actions(self => ({
668
+ /**
669
+ * #action
670
+ */
671
+ zoomIn() {
672
+ self.colWidth = Math.ceil(self.colWidth * 1.5);
673
+ self.rowHeight = Math.ceil(self.rowHeight * 1.5);
674
+ self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
675
+ },
676
+ /**
677
+ * #action
678
+ */
679
+ zoomOut() {
680
+ self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75));
681
+ self.rowHeight = Math.max(1.5, Math.floor(self.rowHeight * 0.75));
682
+ self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
683
+ },
684
+ /**
685
+ * #action
686
+ */
687
+ setLoadedInterProAnnotations(data) {
688
+ self.loadedInterProAnnotations = data;
689
+ },
690
+ /**
691
+ * #action
692
+ */
693
+ doScrollY(deltaY) {
694
+ self.scrollY = clamp(-self.totalHeight + 10, self.scrollY + deltaY, 0);
695
+ },
696
+ /**
697
+ * #action
698
+ */
699
+ doScrollX(deltaX) {
700
+ self.scrollX = clamp(self.maxScrollX, self.scrollX + deltaX, 0);
701
+ },
702
+ /**
703
+ * #action
704
+ */
705
+ setScrollX(n) {
706
+ self.scrollX = clamp(self.maxScrollX, n, 0);
707
+ },
708
+ /**
709
+ * #action
710
+ */
711
+ toggleTrack(id) {
712
+ if (self.turnedOffTracks.has(id)) {
713
+ self.turnedOffTracks.delete(id);
734
714
  }
735
- }
736
- return ret;
737
- },
738
- /**
739
- * #getter
740
- */
741
- get done() {
742
- return self.initialized && (self.data.msa || self.data.tree);
743
- },
744
- /**
745
- * #getter
746
- */
747
- get maxScrollX() {
748
- return -self.totalWidth + (self.msaAreaWidth - 100);
749
- },
750
- }))
751
- .actions(self => ({
752
- /**
753
- * #action
754
- */
755
- addUniprotTrack(node) {
756
- if (self.boxTracks.some(t => t.name === node.name)) {
757
- if (self.turnedOffTracks.has(node.name)) {
758
- this.toggleTrack(node.name);
715
+ else {
716
+ self.turnedOffTracks.set(id, true);
759
717
  }
760
- }
761
- else {
762
- self.boxTracks.push({
763
- ...node,
764
- id: node.name,
765
- associatedRowName: node.name,
766
- });
767
- }
768
- },
769
- /**
770
- * #action
771
- */
772
- doScrollY(deltaY) {
773
- self.scrollY = clamp(-self.totalHeight + 10, self.scrollY + deltaY, 0);
774
- },
775
- /**
776
- * #action
777
- */
778
- doScrollX(deltaX) {
779
- self.scrollX = clamp(self.maxScrollX, self.scrollX + deltaX, 0);
780
- },
781
- /**
782
- * #action
783
- */
784
- setScrollX(n) {
785
- self.scrollX = clamp(self.maxScrollX, n, 0);
786
- },
787
- /**
788
- * #action
789
- */
790
- setMouseoveredColumn(n, chain, file) {
791
- let j = 0;
792
- let i = 0;
793
- const { id } = self.inverseStructures[file.slice(0, -4)] || {};
794
- const row = self.MSA?.getRow(id);
795
- if (row) {
796
- for (i = 0; i < row.length && j < n; i++) {
797
- if (row[i] !== '-') {
798
- j++;
718
+ },
719
+ /**
720
+ * #action
721
+ */
722
+ addInterProScanJobId(arg) {
723
+ self.interProScanJobIds = [
724
+ ...self.interProScanJobIds,
725
+ { jobId: arg, date: +Date.now() },
726
+ ];
727
+ },
728
+ /**
729
+ * #action
730
+ */
731
+ setStatus(status) {
732
+ self.status = status;
733
+ },
734
+ }))
735
+ .views(self => ({
736
+ /**
737
+ * #getter
738
+ */
739
+ get labelsWidth() {
740
+ let x = 0;
741
+ const { rowHeight, hierarchy, treeMetadata, fontSize } = self;
742
+ if (rowHeight > 5) {
743
+ for (const node of hierarchy.leaves()) {
744
+ x = Math.max(measureTextCanvas(treeMetadata[node.data.name]?.genome || node.data.name, fontSize), x);
799
745
  }
800
746
  }
801
- self.mouseCol = j + 1;
802
- }
803
- else {
804
- self.mouseCol = undefined;
805
- }
806
- },
807
- /**
808
- * #action
809
- */
810
- toggleTrack(id) {
811
- if (self.turnedOffTracks.has(id)) {
812
- self.turnedOffTracks.delete(id);
813
- }
814
- else {
815
- self.turnedOffTracks.set(id, true);
816
- }
817
- },
818
- }))
819
- .views(self => ({
820
- /**
821
- * #getter
822
- */
823
- get labelsWidth() {
824
- let x = 0;
825
- const { rowHeight, hierarchy, treeMetadata, fontSize } = self;
826
- if (rowHeight > 5) {
827
- for (const node of hierarchy.leaves()) {
828
- x = Math.max(measureTextCanvas(treeMetadata[node.data.name]?.genome || node.data.name, fontSize), x);
747
+ return x;
748
+ },
749
+ /**
750
+ * #getter
751
+ */
752
+ get secondaryStructureConsensus() {
753
+ return self.MSA?.secondaryStructureConsensus;
754
+ },
755
+ /**
756
+ * #getter
757
+ */
758
+ get seqConsensus() {
759
+ return self.MSA?.seqConsensus;
760
+ },
761
+ /**
762
+ * #getter
763
+ */
764
+ get conservation() {
765
+ if (self.columns2d.length) {
766
+ for (let i = 0; i < self.columns2d[0].length; i++) {
767
+ const col = [];
768
+ for (const column of self.columns2d) {
769
+ col.push(column[i]);
770
+ }
771
+ }
829
772
  }
830
- }
831
- return x;
832
- },
833
- /**
834
- * #getter
835
- */
836
- get secondaryStructureConsensus() {
837
- return self.MSA?.secondaryStructureConsensus;
838
- },
839
- /**
840
- * #getter
841
- */
842
- get seqConsensus() {
843
- return self.MSA?.seqConsensus;
844
- },
845
- /**
846
- * #getter
847
- */
848
- get conservation() {
849
- if (self.columns2d.length) {
850
- for (let i = 0; i < self.columns2d[0].length; i++) {
851
- const col = [];
852
- for (const column of self.columns2d) {
853
- col.push(column[i]);
773
+ return ['a'];
774
+ },
775
+ /**
776
+ * #getter
777
+ */
778
+ get adapterTrackModels() {
779
+ return (self.MSA?.tracks.map(t => ({
780
+ model: {
781
+ ...t,
782
+ data: t.data ? skipBlanks(self.blanks, t.data) : undefined,
783
+ height: self.rowHeight,
784
+ },
785
+ ReactComponent: TextTrack,
786
+ })) || []);
787
+ },
788
+ /**
789
+ * #getter
790
+ */
791
+ get tracks() {
792
+ return this.adapterTrackModels;
793
+ },
794
+ /**
795
+ * #getter
796
+ */
797
+ get turnedOnTracks() {
798
+ return this.tracks.filter(f => !self.turnedOffTracks.has(f.model.id));
799
+ },
800
+ /**
801
+ * #method
802
+ * return a row-specific sequence coordinate, skipping gaps, given a global
803
+ * coordinate
804
+ */
805
+ globalCoordToRowSpecificSeqCoord(rowName, position) {
806
+ const { rowNames, rows } = self;
807
+ const index = rowNames.indexOf(rowName);
808
+ if (index !== -1 && rows[index]) {
809
+ const row = rows[index][1];
810
+ let k = 0;
811
+ for (let i = 0; i < position; i++) {
812
+ if (row[i] !== '-') {
813
+ k++;
814
+ }
815
+ else if (k >= position) {
816
+ break;
817
+ }
854
818
  }
819
+ return k;
855
820
  }
856
- }
857
- return ['a'];
858
- },
859
- /**
860
- * #getter
861
- */
862
- get adapterTrackModels() {
863
- return (self.MSA?.tracks.map(t => ({
864
- model: {
865
- ...t,
866
- data: t.data ? skipBlanks(self.blanks, t.data) : undefined,
867
- height: self.rowHeight,
868
- },
869
- ReactComponent: TextTrack,
870
- })) || []);
871
- },
872
- /**
873
- * #getter
874
- */
875
- get boxTrackModels() {
876
- return self.boxTracks
877
- .filter(track => self.rows.some(row => row[0] === track.name))
878
- .map(track => ({
879
- model: track,
880
- ReactComponent: BoxTrack,
881
- }));
882
- },
883
- /**
884
- * #getter
885
- */
886
- get tracks() {
887
- return [...this.adapterTrackModels, ...this.boxTrackModels];
888
- },
889
- /**
890
- * #getter
891
- */
892
- get turnedOnTracks() {
893
- return this.tracks.filter(f => !self.turnedOffTracks.has(f.model.id));
894
- },
895
- /**
896
- * #method
897
- * returns coordinate in the current relative coordinate scheme
898
- */
899
- pxToBp(coord) {
900
- return Math.floor((coord - self.scrollX) / self.colWidth);
901
- },
902
- /**
903
- * #method
904
- */
905
- rowSpecificBpToPx(rowName, position) {
906
- const { rowNames, rows } = self;
907
- const index = rowNames.indexOf(rowName);
908
- const row = rows[index][1];
909
- const details = self.getRowData(rowName);
910
- const offset = details.range?.start || 0;
911
- const current = position - offset;
912
- const s = new Set(self.blanks);
913
- if (current < 0) {
914
821
  return 0;
915
- }
916
- let j = 0;
917
- let i = 0;
918
- for (; i < row.length; i++) {
919
- if (row[i] !== '-' && j++ === current) {
920
- break;
921
- }
922
- }
923
- let count = 0;
924
- for (let k = 0; k < row.length; k++) {
925
- if (s.has(k) && k < i + 1) {
926
- count++;
927
- }
928
- }
929
- return i - count;
930
- },
931
- /**
932
- * #method
933
- */
934
- globalBpToPx(position) {
935
- let count = 0;
936
- const s = new Set(self.blanks);
937
- for (let k = 0; k < self.rows[0]?.[1].length; k++) {
938
- if (s.has(k) && k < position + 1) {
939
- count++;
822
+ },
823
+ /**
824
+ * #method
825
+ * return a global coordinate given a row-specific sequence coordinate
826
+ * which does not not include gaps
827
+ */
828
+ seqCoordToRowSpecificGlobalCoord(rowName, position) {
829
+ const { rowNames, rows } = self;
830
+ const index = rowNames.indexOf(rowName);
831
+ if (index !== -1 && rows[index]) {
832
+ const row = rows[index][1];
833
+ let k = 0;
834
+ let i = 0;
835
+ for (; k < position; i++) {
836
+ if (row[i] !== '-') {
837
+ k++;
838
+ }
839
+ else if (k >= position) {
840
+ break;
841
+ }
842
+ }
843
+ return i;
940
844
  }
941
- }
942
- return position - count;
943
- },
944
- /**
945
- * #method
946
- */
947
- relativePxToBp(rowName, position) {
948
- const { rowNames, rows } = self;
949
- const index = rowNames.indexOf(rowName);
950
- if (index !== -1 && rows[index]) {
951
- const row = rows[index][1];
952
- let k = 0;
953
- for (let i = 0; i < position; i++) {
954
- if (row[i] !== '-') {
955
- k++;
845
+ return 0;
846
+ },
847
+ }))
848
+ .views(self => ({
849
+ /**
850
+ * #getter
851
+ * total height of track area (px)
852
+ */
853
+ get totalTrackAreaHeight() {
854
+ return sum(self.turnedOnTracks.map(r => r.model.height));
855
+ },
856
+ /**
857
+ * #getter
858
+ */
859
+ get tidyTypes() {
860
+ const types = new Map();
861
+ if (this.tidyAnnotations) {
862
+ for (const { name, accession, description } of this.tidyAnnotations) {
863
+ types.set(accession, { name, accession, description });
956
864
  }
957
- else if (k >= position) {
958
- break;
865
+ }
866
+ return types;
867
+ },
868
+ get tidyAnnotations() {
869
+ const ret = [];
870
+ const { loadedInterProAnnotations } = self;
871
+ if (loadedInterProAnnotations) {
872
+ for (const [id, val] of Object.entries(loadedInterProAnnotations)) {
873
+ for (const { signature, locations } of val.matches) {
874
+ const { entry } = signature;
875
+ if (entry) {
876
+ const { name, accession, description } = entry;
877
+ for (const { start, end } of locations) {
878
+ ret.push({
879
+ id,
880
+ name,
881
+ accession,
882
+ description,
883
+ start,
884
+ end,
885
+ });
886
+ }
887
+ }
888
+ }
959
889
  }
960
890
  }
961
- return k;
962
- }
963
- return 0;
964
- },
965
- /**
966
- * #method
967
- */
968
- relativePxToBp2(rowName, position) {
969
- const { rowNames, rows } = self;
970
- const index = rowNames.indexOf(rowName);
971
- if (index !== -1 && rows[index]) {
972
- const row = rows[index][1];
973
- let k = 0;
891
+ return ret.sort((a, b) => len(b) - len(a));
892
+ },
893
+ /**
894
+ * #getter
895
+ */
896
+ get tidyFilteredAnnotations() {
897
+ return this.tidyAnnotations.filter(r => self.featureFilters.get(r.accession));
898
+ },
899
+ /**
900
+ * #getter
901
+ */
902
+ get tidyFilteredGatheredAnnotations() {
903
+ return groupBy(this.tidyFilteredAnnotations, r => r.id);
904
+ },
905
+ }))
906
+ .views(self => ({
907
+ get fillPalette() {
908
+ const arr = [...self.tidyTypes.keys()];
974
909
  let i = 0;
975
- for (; k < position; i++) {
976
- if (row[i] !== '-') {
977
- k++;
978
- }
979
- else if (k >= position) {
980
- break;
981
- }
910
+ const map = {};
911
+ for (const key of arr) {
912
+ const k = Math.min(arr.length - 1, palettes.length - 1);
913
+ map[key] = palettes[k][i];
914
+ i++;
982
915
  }
983
- return i;
984
- }
985
- return 0;
986
- },
987
- /**
988
- * #method
989
- */
990
- getPos(pos) {
991
- let j = 0;
992
- for (let i = 0, k = 0; i < pos; i++, j++) {
993
- while (j === self.blanks[k]) {
994
- k++;
995
- j++;
916
+ return map;
917
+ },
918
+ get strokePalette() {
919
+ return Object.fromEntries(Object.entries(this.fillPalette).map(([key, val]) => [
920
+ key,
921
+ colord(val).darken(0.1).toHex(),
922
+ ]));
923
+ },
924
+ }))
925
+ .actions(self => ({
926
+ /**
927
+ * #action
928
+ */
929
+ async loadInterProScanResults(jobId) {
930
+ self.setStatus({ msg: 'Loading ' + jobId });
931
+ const ret = await loadInterProScanResults(jobId);
932
+ self.setStatus();
933
+ self.setLoadedInterProAnnotations(Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])));
934
+ },
935
+ /**
936
+ * #action
937
+ */
938
+ async queryInterProScan(programs) {
939
+ const { rows } = self;
940
+ if (rows.length > 140) {
941
+ throw new Error('Too many sequences, please run InterProScan offline');
996
942
  }
997
- }
998
- return j;
999
- },
1000
- }))
1001
- .views(self => ({
1002
- /**
1003
- * #getter
1004
- * total height of track area (px)
1005
- */
1006
- get totalTrackAreaHeight() {
1007
- return sum(self.turnedOnTracks.map(r => r.model.height));
1008
- },
1009
- }))
1010
- .actions(self => ({
1011
- /**
1012
- * #action
1013
- */
1014
- async exportSVG(opts) {
1015
- const { renderToSvg } = await import('./renderToSvg');
1016
- const html = await renderToSvg(self, opts);
1017
- const blob = new Blob([html], { type: 'image/svg+xml' });
1018
- saveAs(blob, 'image.svg');
1019
- },
1020
- /**
1021
- * #action
1022
- * internal, used for drawing to canvas
1023
- */
1024
- incrementRef() {
1025
- self.nref++;
1026
- },
1027
- afterCreate() {
1028
- // autorun opens treeFilehandle
1029
- addDisposer(self, autorun(async () => {
1030
- const { treeFilehandle } = self;
1031
- if (treeFilehandle) {
1032
- try {
1033
- self.setTree(await openLocation(treeFilehandle).readFile('utf8'));
1034
- }
1035
- catch (e) {
1036
- console.error(e);
1037
- self.setError(e);
1038
- }
943
+ const ret = await launchInterProScan({
944
+ algorithm: 'interproscan',
945
+ programs: programs,
946
+ seq: rows
947
+ .map(row => `>${row[0]}\n${row[1].replaceAll('-', '')}`)
948
+ .join('\n'),
949
+ onProgress: arg => self.setStatus(arg),
950
+ onJobId: jobId => self.addInterProScanJobId(jobId),
951
+ });
952
+ self.setLoadedInterProAnnotations(Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])));
953
+ },
954
+ /**
955
+ * #action
956
+ */
957
+ reset() {
958
+ transaction(() => {
959
+ self.setData({ tree: '', msa: '' });
960
+ self.setScrollY(0);
961
+ self.setScrollX(0);
962
+ self.setCurrentAlignment(0);
963
+ self.setTreeFilehandle(undefined);
964
+ self.setMSAFilehandle(undefined);
965
+ });
966
+ },
967
+ /**
968
+ * #action
969
+ */
970
+ async exportSVG(opts) {
971
+ const { renderToSvg } = await import('./renderToSvg');
972
+ const html = await renderToSvg(self, opts);
973
+ const blob = new Blob([html], { type: 'image/svg+xml' });
974
+ saveAs(blob, 'image.svg');
975
+ },
976
+ /**
977
+ * #action
978
+ * internal, used for drawing to canvas
979
+ */
980
+ incrementRef() {
981
+ self.nref++;
982
+ },
983
+ /**
984
+ * #action
985
+ */
986
+ initFilter(arg) {
987
+ const ret = self.featureFilters.get(arg);
988
+ if (ret === undefined) {
989
+ self.featureFilters.set(arg, true);
1039
990
  }
1040
- }));
1041
- // autorun opens treeMetadataFilehandle
1042
- addDisposer(self, autorun(async () => {
1043
- const { treeMetadataFilehandle } = self;
1044
- if (treeMetadataFilehandle) {
1045
- try {
1046
- self.setTreeMetadata(await openLocation(treeMetadataFilehandle).readFile('utf8'));
991
+ },
992
+ /**
993
+ * #action
994
+ */
995
+ setFilter(arg, flag) {
996
+ self.featureFilters.set(arg, flag);
997
+ },
998
+ afterCreate() {
999
+ addDisposer(self, autorun(() => {
1000
+ for (const key of self.tidyTypes.keys()) {
1001
+ this.initFilter(key);
1047
1002
  }
1048
- catch (e) {
1049
- console.error(e);
1050
- self.setError(e);
1003
+ }));
1004
+ addDisposer(self, autorun(async () => {
1005
+ // const res = Object.fromEntries(
1006
+ // await Promise.all(
1007
+ // self.annotationTracks.map(async f => {
1008
+ // const d = await jsonfetch(
1009
+ // `https://jbrowse.org/demos/interproscan/json/${encodeURIComponent(f)}`,
1010
+ // )
1011
+ // return [
1012
+ // decodeURIComponent(f).replace('.json', ''),
1013
+ // d.result.results[0],
1014
+ // ] as const
1015
+ // }),
1016
+ // ),
1017
+ // )
1018
+ // self.setLoadedInterProAnnotations(res)
1019
+ }));
1020
+ // autorun opens treeFilehandle
1021
+ addDisposer(self, autorun(async () => {
1022
+ const { treeFilehandle } = self;
1023
+ if (treeFilehandle) {
1024
+ try {
1025
+ self.setLoadingTree(true);
1026
+ self.setTree(await openLocation(treeFilehandle).readFile('utf8'));
1027
+ if (treeFilehandle.locationType === 'BlobLocation') {
1028
+ // clear filehandle after loading if from a local file
1029
+ self.setTreeFilehandle(undefined);
1030
+ }
1031
+ }
1032
+ catch (e) {
1033
+ console.error(e);
1034
+ self.setError(e);
1035
+ }
1036
+ finally {
1037
+ self.setLoadingTree(false);
1038
+ }
1051
1039
  }
1052
- }
1053
- }));
1054
- // autorun opens msaFilehandle
1055
- addDisposer(self, autorun(async () => {
1056
- const { msaFilehandle } = self;
1057
- if (msaFilehandle) {
1058
- try {
1059
- self.setMSA(await openLocation(msaFilehandle).readFile('utf8'));
1040
+ }));
1041
+ // autorun opens treeMetadataFilehandle
1042
+ addDisposer(self, autorun(async () => {
1043
+ const { treeMetadataFilehandle } = self;
1044
+ if (treeMetadataFilehandle) {
1045
+ try {
1046
+ self.setTreeMetadata(await openLocation(treeMetadataFilehandle).readFile('utf8'));
1047
+ }
1048
+ catch (e) {
1049
+ console.error(e);
1050
+ self.setError(e);
1051
+ }
1060
1052
  }
1061
- catch (e) {
1062
- console.error(e);
1063
- self.setError(e);
1053
+ }));
1054
+ // autorun opens msaFilehandle
1055
+ addDisposer(self, autorun(async () => {
1056
+ const { msaFilehandle } = self;
1057
+ if (msaFilehandle) {
1058
+ try {
1059
+ self.setLoadingMSA(true);
1060
+ const res = await openLocation(msaFilehandle).readFile('utf8');
1061
+ transaction(() => {
1062
+ self.setMSA(res);
1063
+ if (msaFilehandle.locationType === 'BlobLocation') {
1064
+ // clear filehandle after loading if from a local file
1065
+ self.setMSAFilehandle(undefined);
1066
+ }
1067
+ });
1068
+ }
1069
+ catch (e) {
1070
+ console.error(e);
1071
+ self.setError(e);
1072
+ }
1073
+ finally {
1074
+ self.setLoadingMSA(false);
1075
+ }
1064
1076
  }
1065
- }
1066
- }));
1067
- // autorun synchronizes treeWidth with treeAreaWidth
1068
- addDisposer(self, autorun(async () => {
1069
- if (self.treeWidthMatchesArea) {
1070
- self.setTreeWidth(Math.max(50, self.treeAreaWidth - self.labelsWidth - 10 - self.marginLeft));
1071
- }
1072
- }));
1073
- },
1074
- }))
1075
- .postProcessSnapshot(result => {
1076
- const snap = result;
1077
- const { data: { tree, msa, treeMetadata }, ...rest } = snap;
1078
- // remove the MSA/tree data from the tree if the filehandle available in
1079
- // which case it can be reloaded on refresh
1080
- return {
1081
- data: {
1082
- // https://andreasimonecosta.dev/posts/the-shortest-way-to-conditionally-insert-properties-into-an-object-literal/
1083
- ...(!result.treeFilehandle && { tree }),
1084
- ...(!result.msaFilehandle && { msa }),
1085
- ...(!result.treeMetadataFilehandle && { treeMetadata }),
1086
- },
1087
- ...rest,
1088
- };
1089
- });
1090
- export default model;
1077
+ }));
1078
+ // autorun synchronizes treeWidth with treeAreaWidth
1079
+ addDisposer(self, autorun(async () => {
1080
+ if (self.treeWidthMatchesArea) {
1081
+ self.setTreeWidth(Math.max(50, self.treeAreaWidth - self.labelsWidth - 10 - self.marginLeft));
1082
+ }
1083
+ }));
1084
+ addDisposer(self, autorun(() => {
1085
+ localStorageSetItem('msaview-interproscanqueries', JSON.stringify(self.interProScanJobIds));
1086
+ }));
1087
+ },
1088
+ }))
1089
+ .postProcessSnapshot(result => {
1090
+ const snap = result;
1091
+ const { data: { tree, msa, treeMetadata }, ...rest } = snap;
1092
+ // remove the MSA/tree data from the tree if the filehandle available in
1093
+ // which case it can be reloaded on refresh
1094
+ return {
1095
+ data: {
1096
+ ...(result.treeFilehandle ? {} : { tree }),
1097
+ ...(result.msaFilehandle ? {} : { msa }),
1098
+ ...(result.treeMetadataFilehandle ? {} : { treeMetadata }),
1099
+ },
1100
+ ...rest,
1101
+ };
1102
+ });
1103
+ }
1104
+ export default stateModelFactory;
1091
1105
  //# sourceMappingURL=model.js.map