react-msaview 3.1.12 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/bundle/index.js +32 -31
  2. package/dist/colorSchemes.d.ts +2 -2
  3. package/dist/colorSchemes.js +5 -6
  4. package/dist/colorSchemes.js.map +1 -1
  5. package/dist/components/Loading.d.ts +1 -1
  6. package/dist/components/Loading.js +7 -5
  7. package/dist/components/Loading.js.map +1 -1
  8. package/dist/components/MSAView.d.ts +1 -1
  9. package/dist/components/MSAView.js +13 -9
  10. package/dist/components/MSAView.js.map +1 -1
  11. package/dist/components/ResizeHandles.d.ts +1 -1
  12. package/dist/components/ResizeHandles.js +8 -4
  13. package/dist/components/ResizeHandles.js.map +1 -1
  14. package/dist/components/SequenceTextArea.js +9 -3
  15. package/dist/components/SequenceTextArea.js.map +1 -1
  16. package/dist/components/TextTrack.d.ts +1 -1
  17. package/dist/components/TextTrack.js +1 -1
  18. package/dist/components/TextTrack.js.map +1 -1
  19. package/dist/components/Track.d.ts +1 -1
  20. package/dist/components/Track.js +6 -2
  21. package/dist/components/Track.js.map +1 -1
  22. package/dist/components/VerticalScrollbar.d.ts +6 -0
  23. package/dist/components/VerticalScrollbar.js +69 -0
  24. package/dist/components/VerticalScrollbar.js.map +1 -0
  25. package/dist/components/dialogs/AboutDialog.js +3 -1
  26. package/dist/components/dialogs/AboutDialog.js.map +1 -1
  27. package/dist/components/dialogs/AddTrackDialog.d.ts +3 -3
  28. package/dist/components/dialogs/AddTrackDialog.js +8 -3
  29. package/dist/components/dialogs/AddTrackDialog.js.map +1 -1
  30. package/dist/components/dialogs/DomainDialog.d.ts +1 -1
  31. package/dist/components/dialogs/DomainDialog.js +8 -4
  32. package/dist/components/dialogs/DomainDialog.js.map +1 -1
  33. package/dist/components/dialogs/ExportSVGDialog.d.ts +1 -1
  34. package/dist/components/dialogs/ExportSVGDialog.js +29 -17
  35. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
  36. package/dist/components/dialogs/FeatureDialog.d.ts +1 -1
  37. package/dist/components/dialogs/FeatureDialog.js +8 -4
  38. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  39. package/dist/components/dialogs/{InterProScanPanel.d.ts → InterProScanDialog.d.ts} +1 -1
  40. package/dist/components/dialogs/{InterProScanPanel.js → InterProScanDialog.js} +26 -11
  41. package/dist/components/dialogs/InterProScanDialog.js.map +1 -0
  42. package/dist/components/dialogs/MetadataDialog.d.ts +1 -1
  43. package/dist/components/dialogs/MetadataDialog.js +3 -1
  44. package/dist/components/dialogs/MetadataDialog.js.map +1 -1
  45. package/dist/components/dialogs/SettingsDialog.d.ts +1 -1
  46. package/dist/components/dialogs/SettingsDialog.js +62 -15
  47. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  48. package/dist/components/dialogs/TracklistDialog.d.ts +3 -3
  49. package/dist/components/dialogs/TracklistDialog.js +8 -3
  50. package/dist/components/dialogs/TracklistDialog.js.map +1 -1
  51. package/dist/components/dialogs/UserProvidedDomainsDialog.d.ts +7 -0
  52. package/dist/components/dialogs/UserProvidedDomainsDialog.js +64 -0
  53. package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -0
  54. package/dist/components/header/Header.d.ts +1 -1
  55. package/dist/components/header/Header.js +11 -4
  56. package/dist/components/header/Header.js.map +1 -1
  57. package/dist/components/header/HeaderInfoArea.d.ts +1 -1
  58. package/dist/components/header/HeaderInfoArea.js +5 -2
  59. package/dist/components/header/HeaderInfoArea.js.map +1 -1
  60. package/dist/components/header/HeaderMenu.d.ts +1 -1
  61. package/dist/components/header/HeaderMenu.js +12 -4
  62. package/dist/components/header/HeaderMenu.js.map +1 -1
  63. package/dist/components/header/HeaderMenuExtra.d.ts +1 -1
  64. package/dist/components/header/HeaderMenuExtra.js +55 -35
  65. package/dist/components/header/HeaderMenuExtra.js.map +1 -1
  66. package/dist/components/header/HeaderStatusArea.d.ts +2 -2
  67. package/dist/components/header/HeaderStatusArea.js +1 -1
  68. package/dist/components/header/HeaderStatusArea.js.map +1 -1
  69. package/dist/components/header/MultiAlignmentSelector.d.ts +1 -1
  70. package/dist/components/header/ZoomControls.js +45 -3
  71. package/dist/components/header/ZoomControls.js.map +1 -1
  72. package/dist/components/import/ImportForm.d.ts +3 -3
  73. package/dist/components/import/ImportForm.js +15 -2
  74. package/dist/components/import/ImportForm.js.map +1 -1
  75. package/dist/components/import/ImportFormExamples.d.ts +1 -1
  76. package/dist/components/import/ImportFormExamples.js +53 -38
  77. package/dist/components/import/ImportFormExamples.js.map +1 -1
  78. package/dist/components/import/util.d.ts +2 -2
  79. package/dist/components/minimap/Minimap.d.ts +1 -1
  80. package/dist/components/minimap/Minimap.js +24 -17
  81. package/dist/components/minimap/Minimap.js.map +1 -1
  82. package/dist/components/minimap/MinimapSVG.d.ts +1 -1
  83. package/dist/components/minimap/MinimapSVG.js +1 -1
  84. package/dist/components/minimap/MinimapSVG.js.map +1 -1
  85. package/dist/components/msa/MSACanvas.d.ts +1 -1
  86. package/dist/components/msa/MSACanvas.js +3 -3
  87. package/dist/components/msa/MSACanvas.js.map +1 -1
  88. package/dist/components/msa/MSACanvasBlock.d.ts +3 -3
  89. package/dist/components/msa/MSACanvasBlock.js +9 -6
  90. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  91. package/dist/components/msa/MSAMouseoverCanvas.d.ts +1 -1
  92. package/dist/components/msa/MSAPanel.d.ts +1 -1
  93. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +1 -1
  94. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +3 -4
  95. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  96. package/dist/components/msa/renderMSABlock.d.ts +2 -2
  97. package/dist/components/msa/renderMSABlock.js +16 -16
  98. package/dist/components/msa/renderMSABlock.js.map +1 -1
  99. package/dist/components/msa/renderMSAMouseover.d.ts +1 -1
  100. package/dist/components/msa/renderMSAMouseover.js +3 -3
  101. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  102. package/dist/components/tree/TreeBranchMenu.d.ts +1 -1
  103. package/dist/components/tree/TreeBranchMenu.js +6 -3
  104. package/dist/components/tree/TreeBranchMenu.js.map +1 -1
  105. package/dist/components/tree/TreeCanvas.d.ts +1 -1
  106. package/dist/components/tree/TreeCanvas.js +13 -12
  107. package/dist/components/tree/TreeCanvas.js.map +1 -1
  108. package/dist/components/tree/TreeCanvasBlock.d.ts +1 -1
  109. package/dist/components/tree/TreeCanvasBlock.js +13 -5
  110. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  111. package/dist/components/tree/TreeNodeMenu.d.ts +1 -1
  112. package/dist/components/tree/TreeNodeMenu.js +3 -3
  113. package/dist/components/tree/TreeNodeMenu.js.map +1 -1
  114. package/dist/components/tree/TreePanel.d.ts +1 -1
  115. package/dist/components/tree/TreeRuler.d.ts +1 -1
  116. package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +3 -3
  117. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +5 -2
  118. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  119. package/dist/components/tree/renderTreeCanvas.d.ts +3 -3
  120. package/dist/components/tree/renderTreeCanvas.js +25 -9
  121. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  122. package/dist/components/util.js +1 -4
  123. package/dist/components/util.js.map +1 -1
  124. package/dist/ggplotPalettes.js.map +1 -1
  125. package/dist/launchInterProScan.d.ts +1 -1
  126. package/dist/launchInterProScan.js +11 -13
  127. package/dist/launchInterProScan.js.map +1 -1
  128. package/dist/model/DataModel.d.ts +5 -1
  129. package/dist/model/DataModel.js +10 -1
  130. package/dist/model/DataModel.js.map +1 -1
  131. package/dist/model/DialogQueue.d.ts +1 -1
  132. package/dist/model/DialogQueue.js +0 -1
  133. package/dist/model/DialogQueue.js.map +1 -1
  134. package/dist/model.d.ts +187 -35
  135. package/dist/model.js +317 -94
  136. package/dist/model.js.map +1 -1
  137. package/dist/parseGFF.js +8 -6
  138. package/dist/parseGFF.js.map +1 -1
  139. package/dist/parseNewick.js +1 -2
  140. package/dist/parseNewick.js.map +1 -1
  141. package/dist/parsers/ClustalMSA.d.ts +2 -2
  142. package/dist/parsers/ClustalMSA.js.map +1 -1
  143. package/dist/parsers/FastaMSA.d.ts +1 -1
  144. package/dist/parsers/FastaMSA.js +3 -3
  145. package/dist/parsers/FastaMSA.js.map +1 -1
  146. package/dist/parsers/StockholmMSA.d.ts +7 -7
  147. package/dist/parsers/StockholmMSA.js +4 -4
  148. package/dist/parsers/StockholmMSA.js.map +1 -1
  149. package/dist/renderToSvg.d.ts +2 -2
  150. package/dist/renderToSvg.js +6 -11
  151. package/dist/renderToSvg.js.map +1 -1
  152. package/dist/reparseTree.d.ts +1 -1
  153. package/dist/rowCoordinateCalculations.d.ts +2 -0
  154. package/dist/rowCoordinateCalculations.js +26 -0
  155. package/dist/rowCoordinateCalculations.js.map +1 -0
  156. package/dist/rowCoordinateCalculations.test.d.ts +1 -0
  157. package/dist/rowCoordinateCalculations.test.js +18 -0
  158. package/dist/rowCoordinateCalculations.test.js.map +1 -0
  159. package/dist/util.d.ts +2 -2
  160. package/dist/util.js +0 -2
  161. package/dist/util.js.map +1 -1
  162. package/dist/version.d.ts +1 -1
  163. package/dist/version.js +1 -1
  164. package/dist/version.js.map +1 -1
  165. package/package.json +10 -3
  166. package/src/colorSchemes.ts +7 -6
  167. package/src/components/Checkbox2.tsx +1 -1
  168. package/src/components/Loading.tsx +18 -6
  169. package/src/components/MSAView.tsx +27 -18
  170. package/src/components/ResizeHandles.tsx +9 -5
  171. package/src/components/SequenceTextArea.tsx +10 -4
  172. package/src/components/TextTrack.tsx +3 -3
  173. package/src/components/Track.tsx +9 -5
  174. package/src/components/VerticalScrollbar.tsx +89 -0
  175. package/src/components/dialogs/AboutDialog.tsx +7 -1
  176. package/src/components/dialogs/AddTrackDialog.tsx +15 -5
  177. package/src/components/dialogs/DomainDialog.tsx +12 -5
  178. package/src/components/dialogs/ExportSVGDialog.tsx +37 -18
  179. package/src/components/dialogs/FeatureDialog.tsx +10 -8
  180. package/src/components/dialogs/{InterProScanPanel.tsx → InterProScanDialog.tsx} +30 -13
  181. package/src/components/dialogs/MetadataDialog.tsx +9 -2
  182. package/src/components/dialogs/SettingsDialog.tsx +98 -19
  183. package/src/components/dialogs/TracklistDialog.tsx +18 -4
  184. package/src/components/dialogs/UserProvidedDomainsDialog.tsx +139 -0
  185. package/src/components/header/Header.tsx +12 -5
  186. package/src/components/header/HeaderInfoArea.tsx +4 -3
  187. package/src/components/header/HeaderMenu.tsx +13 -8
  188. package/src/components/header/HeaderMenuExtra.tsx +59 -43
  189. package/src/components/header/HeaderStatusArea.tsx +2 -6
  190. package/src/components/header/MultiAlignmentSelector.tsx +1 -1
  191. package/src/components/header/ZoomControls.tsx +52 -2
  192. package/src/components/import/ImportForm.tsx +16 -4
  193. package/src/components/import/ImportFormExamples.tsx +77 -64
  194. package/src/components/import/util.ts +2 -2
  195. package/src/components/minimap/Minimap.tsx +34 -29
  196. package/src/components/minimap/MinimapSVG.tsx +2 -2
  197. package/src/components/msa/MSACanvas.tsx +11 -4
  198. package/src/components/msa/MSACanvasBlock.tsx +10 -7
  199. package/src/components/msa/MSAMouseoverCanvas.tsx +1 -1
  200. package/src/components/msa/MSAPanel.tsx +1 -1
  201. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +8 -9
  202. package/src/components/msa/renderMSABlock.ts +44 -24
  203. package/src/components/msa/renderMSAMouseover.ts +4 -4
  204. package/src/components/tree/TreeBranchMenu.tsx +6 -4
  205. package/src/components/tree/TreeCanvas.tsx +15 -16
  206. package/src/components/tree/TreeCanvasBlock.tsx +14 -6
  207. package/src/components/tree/TreeNodeMenu.tsx +4 -4
  208. package/src/components/tree/TreePanel.tsx +1 -1
  209. package/src/components/tree/TreeRuler.tsx +1 -1
  210. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +12 -3
  211. package/src/components/tree/renderTreeCanvas.ts +32 -12
  212. package/src/components/util.ts +2 -5
  213. package/src/ggplotPalettes.ts +1 -1
  214. package/src/launchInterProScan.ts +13 -15
  215. package/src/model/DataModel.ts +10 -0
  216. package/src/model/DialogQueue.ts +1 -2
  217. package/src/model.ts +355 -112
  218. package/src/parseGFF.ts +13 -11
  219. package/src/parseNewick.ts +4 -4
  220. package/src/parsers/ClustalMSA.ts +3 -3
  221. package/src/parsers/FastaMSA.ts +5 -5
  222. package/src/parsers/StockholmMSA.ts +11 -11
  223. package/src/renderToSvg.tsx +7 -8
  224. package/src/reparseTree.ts +1 -1
  225. package/src/rowCoordinateCalculations.test.ts +19 -0
  226. package/src/rowCoordinateCalculations.ts +26 -0
  227. package/src/util.ts +2 -4
  228. package/src/version.ts +1 -1
  229. package/dist/components/dialogs/InterProScanPanel.js.map +0 -1
  230. package/dist/components/dialogs/UserProvidedResultPanel.d.ts +0 -7
  231. package/dist/components/dialogs/UserProvidedResultPanel.js +0 -56
  232. package/dist/components/dialogs/UserProvidedResultPanel.js.map +0 -1
  233. package/src/components/dialogs/UserProvidedResultPanel.tsx +0 -119
package/dist/model.js CHANGED
@@ -4,10 +4,14 @@ import { hierarchy, cluster } from 'd3-hierarchy';
4
4
  import { ascending } from 'd3-array';
5
5
  import Stockholm from 'stockholm-js';
6
6
  import { saveAs } from 'file-saver';
7
+ import { ungzip } from 'pako';
7
8
  // jbrowse
8
9
  import { FileLocation, ElementId } from '@jbrowse/core/util/types/mst';
9
10
  import { openLocation } from '@jbrowse/core/util/io';
10
- import { groupBy, notEmpty, sum, } from '@jbrowse/core/util';
11
+ import { groupBy, notEmpty, sum } from '@jbrowse/core/util';
12
+ export function isGzip(buf) {
13
+ return buf[0] === 31 && buf[1] === 139 && buf[2] === 8;
14
+ }
11
15
  // locals
12
16
  import { clamp, collapse, generateNodeIds, maxLength, setBrLength, skipBlanks, len, } from './util';
13
17
  import { colord } from 'colord';
@@ -28,6 +32,7 @@ import { DataModelF } from './model/DataModel';
28
32
  import { DialogQueueSessionMixin } from './model/DialogQueue';
29
33
  import { TreeF } from './model/treeModel';
30
34
  import { MSAModelF } from './model/msaModel';
35
+ import { mouseOverCoordToGlobalCoord, globalCoordToRowSpecificCoord, } from './rowCoordinateCalculations';
31
36
  /**
32
37
  * #stateModel MsaView
33
38
  * extends
@@ -47,6 +52,14 @@ function stateModelFactory() {
47
52
  * #property
48
53
  */
49
54
  showDomains: false,
55
+ /**
56
+ * #property
57
+ */
58
+ allowedGappyness: 100,
59
+ /**
60
+ * #property
61
+ */
62
+ contrastLettering: true,
50
63
  /**
51
64
  * #property
52
65
  */
@@ -56,6 +69,18 @@ function stateModelFactory() {
56
69
  * hardcoded view type
57
70
  */
58
71
  type: types.literal('MsaView'),
72
+ /**
73
+ * #property
74
+ */
75
+ drawMsaLetters: true,
76
+ /**
77
+ * #property
78
+ */
79
+ hideGaps: true,
80
+ /**
81
+ * #property
82
+ */
83
+ drawTreeText: true,
59
84
  /**
60
85
  * #property
61
86
  * height of the div containing the view, px
@@ -104,14 +129,16 @@ function stateModelFactory() {
104
129
  currentAlignment: 0,
105
130
  /**
106
131
  * #property
107
- * array of tree parent nodes that are 'collapsed'
132
+ * array of tree parent nodes that are 'collapsed' (all children are
133
+ * hidden)
108
134
  */
109
135
  collapsed: types.array(types.string),
110
136
  /**
111
137
  * #property
112
- * array of tree leaf nodes that are 'collapsed'
138
+ * array of tree leaf nodes that are 'collapsed' (just that leaf node
139
+ * is hidden)
113
140
  */
114
- collapsed2: types.array(types.string),
141
+ collapsedLeaves: types.array(types.string),
115
142
  /**
116
143
  * #property
117
144
  * focus on particular subtree
@@ -134,6 +161,13 @@ function stateModelFactory() {
134
161
  featureFilters: types.map(types.boolean),
135
162
  }))
136
163
  .volatile(() => ({
164
+ /**
165
+ * #volatile
166
+ */
167
+ headerHeight: 0,
168
+ /**
169
+ * #volatile
170
+ */
137
171
  status: undefined,
138
172
  /**
139
173
  * #volatile
@@ -152,7 +186,7 @@ function stateModelFactory() {
152
186
  /**
153
187
  * #volatile
154
188
  */
155
- width: 800,
189
+ volatileWidth: undefined,
156
190
  /**
157
191
  * #volatile
158
192
  * resize handle width between tree and msa area, px
@@ -162,7 +196,7 @@ function stateModelFactory() {
162
196
  * #volatile
163
197
  * size of blocks of content to be drawn, px
164
198
  */
165
- blockSize: 1000,
199
+ blockSize: 500,
166
200
  /**
167
201
  * #volatile
168
202
  * the currently mouse-hovered row
@@ -209,9 +243,27 @@ function stateModelFactory() {
209
243
  * #volatile
210
244
  *
211
245
  */
212
- loadedInterProAnnotations: undefined,
246
+ interProAnnotations: undefined,
213
247
  }))
214
248
  .actions(self => ({
249
+ /**
250
+ * #action
251
+ */
252
+ setHideGaps(arg) {
253
+ self.hideGaps = arg;
254
+ },
255
+ /**
256
+ * #action
257
+ */
258
+ setAllowedGappyness(arg) {
259
+ self.allowedGappyness = arg;
260
+ },
261
+ /**
262
+ * #action
263
+ */
264
+ setContrastLettering(arg) {
265
+ self.contrastLettering = arg;
266
+ },
215
267
  /**
216
268
  * #action
217
269
  */
@@ -228,7 +280,7 @@ function stateModelFactory() {
228
280
  * #action
229
281
  */
230
282
  setWidth(arg) {
231
- self.width = arg;
283
+ self.volatileWidth = arg;
232
284
  },
233
285
  /**
234
286
  * #action
@@ -315,11 +367,11 @@ function stateModelFactory() {
315
367
  * #action
316
368
  */
317
369
  toggleCollapsed2(node) {
318
- if (self.collapsed2.includes(node)) {
319
- self.collapsed2.remove(node);
370
+ if (self.collapsedLeaves.includes(node)) {
371
+ self.collapsedLeaves.remove(node);
320
372
  }
321
373
  else {
322
- self.collapsed2.push(node);
374
+ self.collapsedLeaves.push(node);
323
375
  }
324
376
  },
325
377
  /**
@@ -364,6 +416,35 @@ function stateModelFactory() {
364
416
  setTreeMetadata(result) {
365
417
  self.data.setTreeMetadata(result);
366
418
  },
419
+ }))
420
+ .views(self => ({
421
+ /**
422
+ * #getter
423
+ */
424
+ get realAllowedGappyness() {
425
+ return self.hideGaps ? self.allowedGappyness : 100;
426
+ },
427
+ /**
428
+ * #getter
429
+ */
430
+ get actuallyShowDomains() {
431
+ return self.showDomains && !!self.interProAnnotations;
432
+ },
433
+ /**
434
+ * #getter
435
+ */
436
+ get viewInitialized() {
437
+ return self.volatileWidth !== undefined;
438
+ },
439
+ /**
440
+ * #getter
441
+ */
442
+ get width() {
443
+ if (self.volatileWidth === undefined) {
444
+ throw new Error('not initialized');
445
+ }
446
+ return self.volatileWidth;
447
+ },
367
448
  }))
368
449
  .views(self => ({
369
450
  /**
@@ -403,18 +484,18 @@ function stateModelFactory() {
403
484
  * #getter
404
485
  */
405
486
  get noTree() {
406
- return !!this._tree.noTree;
487
+ return !!this.tree.noTree;
407
488
  },
408
489
  /**
409
490
  * #getter
410
491
  */
411
- get noAnnotations() {
412
- return !self.loadedInterProAnnotations;
492
+ get noDomains() {
493
+ return !self.interProAnnotations;
413
494
  },
414
495
  /**
415
496
  * #getter
416
497
  */
417
- get menuItems() {
498
+ menuItems() {
418
499
  return [];
419
500
  },
420
501
  /**
@@ -432,12 +513,10 @@ function stateModelFactory() {
432
513
  if (Stockholm.sniff(text)) {
433
514
  return new StockholmMSA(text, self.currentAlignment);
434
515
  }
435
- else if (text.startsWith('>')) {
516
+ if (text.startsWith('>')) {
436
517
  return new FastaMSA(text);
437
518
  }
438
- else {
439
- return new ClustalMSA(text);
440
- }
519
+ return new ClustalMSA(text);
441
520
  }
442
521
  return null;
443
522
  },
@@ -450,7 +529,7 @@ function stateModelFactory() {
450
529
  /**
451
530
  * #getter
452
531
  */
453
- get _tree() {
532
+ get tree() {
454
533
  const ret = self.data.tree
455
534
  ? generateNodeIds(parseNewick(self.data.tree))
456
535
  : this.MSA?.getTree() || {
@@ -465,7 +544,7 @@ function stateModelFactory() {
465
544
  * #getter
466
545
  */
467
546
  get rowNames() {
468
- return this.hierarchy.leaves().map(n => n.data.name);
547
+ return this.leaves.map(n => n.data.name);
469
548
  },
470
549
  /**
471
550
  * #getter
@@ -478,7 +557,9 @@ function stateModelFactory() {
478
557
  * #getter
479
558
  */
480
559
  get root() {
481
- let hier = hierarchy(this._tree, d => d.branchset)
560
+ let hier = hierarchy(this.tree, d => d.branchset)
561
+ // todo: investigate whether needed, typescript says branchset always true
562
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
482
563
  .sum(d => (d.branchset ? 0 : 1))
483
564
  .sort((a, b) => ascending(a.data.length || 1, b.data.length || 1));
484
565
  if (self.showOnly) {
@@ -488,10 +569,12 @@ function stateModelFactory() {
488
569
  }
489
570
  }
490
571
  ;
491
- [...self.collapsed, ...self.collapsed2]
572
+ [...self.collapsed, ...self.collapsedLeaves]
492
573
  .map(collapsedId => hier.find(node => node.data.id === collapsedId))
493
574
  .filter(notEmpty)
494
- .map(node => collapse(node));
575
+ .map(node => {
576
+ collapse(node);
577
+ });
495
578
  return hier;
496
579
  },
497
580
  /**
@@ -511,34 +594,49 @@ function stateModelFactory() {
511
594
  * #getter
512
595
  */
513
596
  get blanks() {
597
+ const { hideGaps, realAllowedGappyness } = self;
514
598
  const blanks = [];
515
- const strs = this.hierarchy
516
- .leaves()
517
- .map(leaf => this.MSA?.getRow(leaf.data.name))
518
- .filter((item) => !!item);
519
- for (let i = 0; i < strs[0]?.length; i++) {
520
- let counter = 0;
521
- for (const str of strs) {
522
- if (str[i] === '-') {
523
- counter++;
599
+ if (hideGaps) {
600
+ const strs = this.leaves
601
+ .map(leaf => this.MSA?.getRow(leaf.data.name))
602
+ .filter((item) => !!item);
603
+ if (strs.length) {
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++;
609
+ }
610
+ }
611
+ if (counter / strs.length >= realAllowedGappyness / 100) {
612
+ blanks.push(i);
613
+ }
524
614
  }
525
615
  }
526
- if (counter === strs.length) {
527
- blanks.push(i);
528
- }
529
616
  }
530
617
  return blanks;
531
618
  },
619
+ /**
620
+ * #getter
621
+ */
622
+ get blanksSet() {
623
+ return new Set(this.blanks);
624
+ },
532
625
  /**
533
626
  * #getter
534
627
  */
535
628
  get rows() {
536
629
  const MSA = this.MSA;
537
- return this.hierarchy
538
- .leaves()
630
+ return this.leaves
539
631
  .map(leaf => [leaf.data.name, MSA?.getRow(leaf.data.name)])
540
632
  .filter((f) => !!f[1]);
541
633
  },
634
+ /**
635
+ * #getter
636
+ */
637
+ get rowMap() {
638
+ return new Map(this.rows);
639
+ },
542
640
  /**
543
641
  * #getter
544
642
  */
@@ -566,15 +664,24 @@ function stateModelFactory() {
566
664
  for (const column of columns) {
567
665
  for (let j = 0; j < column.length; j++) {
568
666
  const l = r[j] || {};
569
- if (!l[column[j]]) {
570
- l[column[j]] = 0;
667
+ const cj = column[j];
668
+ if (!l[cj]) {
669
+ l[cj] = 0;
571
670
  }
572
- l[column[j]]++;
671
+ l[cj]++;
573
672
  r[j] = l;
574
673
  }
575
674
  }
576
675
  return r;
577
676
  },
677
+ /**
678
+ * #getter
679
+ */
680
+ get colStatsSums() {
681
+ return Object.fromEntries(Object.entries(this.colStats).map(([key, val]) => {
682
+ return [key, sum(Object.values(val))];
683
+ }));
684
+ },
578
685
  /**
579
686
  * #getter
580
687
  * generates a new tree that is clustered with x,y positions
@@ -594,6 +701,12 @@ function stateModelFactory() {
594
701
  get totalHeight() {
595
702
  return this.root.leaves().length * self.rowHeight;
596
703
  },
704
+ /**
705
+ * #getter
706
+ */
707
+ get leaves() {
708
+ return this.hierarchy.leaves();
709
+ },
597
710
  }))
598
711
  .views(self => ({
599
712
  /**
@@ -607,7 +720,7 @@ function stateModelFactory() {
607
720
  /**
608
721
  * #getter
609
722
  */
610
- get initialized() {
723
+ get dataInitialized() {
611
724
  return (self.data.msa || self.data.tree) && !self.error;
612
725
  },
613
726
  /**
@@ -658,29 +771,77 @@ function stateModelFactory() {
658
771
  get maxScrollX() {
659
772
  return -self.totalWidth + (self.msaAreaWidth - 100);
660
773
  },
774
+ /**
775
+ * #getter
776
+ */
777
+ get showMsaLetters() {
778
+ return self.drawMsaLetters && self.rowHeight >= 5;
779
+ },
780
+ /**
781
+ * #getter
782
+ */
783
+ get showTreeText() {
784
+ return self.drawLabels && self.rowHeight >= 5;
785
+ },
661
786
  }))
662
787
  .actions(self => ({
663
788
  /**
664
789
  * #action
665
790
  */
666
- zoomIn() {
791
+ setDrawMsaLetters(arg) {
792
+ self.drawMsaLetters = arg;
793
+ },
794
+ /**
795
+ * #action
796
+ */
797
+ zoomOutHorizontal() {
798
+ self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75));
799
+ self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
800
+ },
801
+ /**
802
+ * #action
803
+ */
804
+ zoomInHorizontal() {
667
805
  self.colWidth = Math.ceil(self.colWidth * 1.5);
668
- self.rowHeight = Math.ceil(self.rowHeight * 1.5);
669
806
  self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
670
807
  },
671
808
  /**
672
809
  * #action
673
810
  */
674
- zoomOut() {
675
- self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75));
811
+ zoomInVertical() {
812
+ self.rowHeight = Math.ceil(self.rowHeight * 1.5);
813
+ },
814
+ /**
815
+ * #action
816
+ */
817
+ zoomOutVertical() {
676
818
  self.rowHeight = Math.max(1.5, Math.floor(self.rowHeight * 0.75));
677
- self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
678
819
  },
679
820
  /**
680
821
  * #action
681
822
  */
682
- setLoadedInterProAnnotations(data) {
683
- self.loadedInterProAnnotations = data;
823
+ zoomIn() {
824
+ transaction(() => {
825
+ self.colWidth = Math.ceil(self.colWidth * 1.5);
826
+ self.rowHeight = Math.ceil(self.rowHeight * 1.5);
827
+ self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
828
+ });
829
+ },
830
+ /**
831
+ * #action
832
+ */
833
+ zoomOut() {
834
+ transaction(() => {
835
+ self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75));
836
+ self.rowHeight = Math.max(1.5, Math.floor(self.rowHeight * 0.75));
837
+ self.scrollX = clamp(self.maxScrollX, self.scrollX, 0);
838
+ });
839
+ },
840
+ /**
841
+ * #action
842
+ */
843
+ setInterProAnnotations(data) {
844
+ self.interProAnnotations = data;
684
845
  },
685
846
  /**
686
847
  * #action
@@ -724,9 +885,9 @@ function stateModelFactory() {
724
885
  */
725
886
  get labelsWidth() {
726
887
  let x = 0;
727
- const { rowHeight, hierarchy, treeMetadata, fontSize } = self;
888
+ const { rowHeight, leaves, treeMetadata, fontSize } = self;
728
889
  if (rowHeight > 5) {
729
- for (const node of hierarchy.leaves()) {
890
+ for (const node of leaves) {
730
891
  x = Math.max(measureTextCanvas(treeMetadata[node.data.name]?.genome || node.data.name, fontSize), x);
731
892
  }
732
893
  }
@@ -783,28 +944,42 @@ function stateModelFactory() {
783
944
  get turnedOnTracks() {
784
945
  return this.tracks.filter(f => !self.turnedOffTracks.has(f.model.id));
785
946
  },
947
+ /**
948
+ * #getter
949
+ */
950
+ get showHorizontalScrollbar() {
951
+ return self.msaAreaWidth < self.totalWidth;
952
+ },
953
+ /**
954
+ * #getter
955
+ */
956
+ get rowNamesSet() {
957
+ return new Map(self.rowNames.map((r, idx) => [r, idx]));
958
+ },
786
959
  /**
787
960
  * #method
788
- * return a row-specific sequence coordinate, skipping gaps, given a global
789
- * coordinate
961
+ * return a row-specific letter, or undefined if gap
790
962
  */
791
- globalCoordToRowSpecificSeqCoord(rowName, position) {
792
- const { rowNames, rows } = self;
793
- const index = rowNames.indexOf(rowName);
794
- if (index !== -1 && rows[index]) {
795
- const row = rows[index][1];
796
- let k = 0;
797
- for (let i = 0; i < position; i++) {
798
- if (row[i] !== '-') {
799
- k++;
800
- }
801
- else if (k >= position) {
802
- break;
803
- }
804
- }
805
- return k;
963
+ mouseOverCoordToRowLetter(rowName, position) {
964
+ const { rowMap, blanks } = self;
965
+ return rowMap.get(rowName)?.[mouseOverCoordToGlobalCoord(blanks, position)];
966
+ },
967
+ /**
968
+ * #method
969
+ * return a row-specific sequence coordinate, skipping gaps, given a
970
+ * global coordinate
971
+ */
972
+ mouseOverCoordToGapRemovedRowCoord(rowName, position) {
973
+ const { rowMap, blanks } = self;
974
+ const seq = rowMap.get(rowName);
975
+ if (seq !== undefined) {
976
+ const pos2 = mouseOverCoordToGlobalCoord(blanks, position);
977
+ const pos1 = globalCoordToRowSpecificCoord(seq, pos2);
978
+ return seq[pos1] === '-' || !seq[pos1] ? undefined : pos1;
979
+ }
980
+ else {
981
+ return undefined;
806
982
  }
807
- return 0;
808
983
  },
809
984
  /**
810
985
  * #method
@@ -832,6 +1007,15 @@ function stateModelFactory() {
832
1007
  },
833
1008
  }))
834
1009
  .views(self => ({
1010
+ /**
1011
+ * #getter
1012
+ * widget width minus the tree area gives the space for the MSA
1013
+ */
1014
+ get msaAreaHeight() {
1015
+ return (self.height -
1016
+ (self.showHorizontalScrollbar ? self.minimapHeight : 0) -
1017
+ self.headerHeight);
1018
+ },
835
1019
  /**
836
1020
  * #getter
837
1021
  * total height of track area (px)
@@ -842,20 +1026,21 @@ function stateModelFactory() {
842
1026
  /**
843
1027
  * #getter
844
1028
  */
845
- get tidyTypes() {
1029
+ get tidyInterProAnnotationTypes() {
846
1030
  const types = new Map();
847
- if (this.tidyAnnotations) {
848
- for (const { name, accession, description } of this.tidyAnnotations) {
849
- types.set(accession, { name, accession, description });
850
- }
1031
+ for (const annot of this.tidyInterProAnnotations) {
1032
+ types.set(annot.accession, annot);
851
1033
  }
852
1034
  return types;
853
1035
  },
854
- get tidyAnnotations() {
1036
+ /**
1037
+ * #getter
1038
+ */
1039
+ get tidyInterProAnnotations() {
855
1040
  const ret = [];
856
- const { loadedInterProAnnotations } = self;
857
- if (loadedInterProAnnotations) {
858
- for (const [id, val] of Object.entries(loadedInterProAnnotations)) {
1041
+ const { interProAnnotations } = self;
1042
+ if (interProAnnotations) {
1043
+ for (const [id, val] of Object.entries(interProAnnotations)) {
859
1044
  for (const { signature, locations } of val.matches) {
860
1045
  const { entry } = signature;
861
1046
  if (entry) {
@@ -879,19 +1064,36 @@ function stateModelFactory() {
879
1064
  /**
880
1065
  * #getter
881
1066
  */
882
- get tidyFilteredAnnotations() {
883
- return this.tidyAnnotations.filter(r => self.featureFilters.get(r.accession));
1067
+ get tidyFilteredInterProAnnotations() {
1068
+ return this.tidyInterProAnnotations.filter(r => self.featureFilters.get(r.accession));
1069
+ },
1070
+ /**
1071
+ * #getter
1072
+ */
1073
+ get tidyFilteredGatheredInterProAnnotations() {
1074
+ return groupBy(this.tidyFilteredInterProAnnotations, r => r.id);
884
1075
  },
1076
+ }))
1077
+ .views(self => ({
885
1078
  /**
886
1079
  * #getter
887
1080
  */
888
- get tidyFilteredGatheredAnnotations() {
889
- return groupBy(this.tidyFilteredAnnotations, r => r.id);
1081
+ get showVerticalScrollbar() {
1082
+ return self.msaAreaHeight < self.totalHeight;
890
1083
  },
891
1084
  }))
892
1085
  .views(self => ({
1086
+ /**
1087
+ * #getter
1088
+ */
1089
+ get verticalScrollbarWidth() {
1090
+ return self.showVerticalScrollbar ? 20 : 0;
1091
+ },
1092
+ /**
1093
+ * #getter
1094
+ */
893
1095
  get fillPalette() {
894
- const arr = [...self.tidyTypes.keys()];
1096
+ const arr = [...self.tidyInterProAnnotationTypes.keys()];
895
1097
  let i = 0;
896
1098
  const map = {};
897
1099
  for (const key of arr) {
@@ -901,6 +1103,9 @@ function stateModelFactory() {
901
1103
  }
902
1104
  return map;
903
1105
  },
1106
+ /**
1107
+ * #getter
1108
+ */
904
1109
  get strokePalette() {
905
1110
  return Object.fromEntries(Object.entries(this.fillPalette).map(([key, val]) => [
906
1111
  key,
@@ -909,18 +1114,23 @@ function stateModelFactory() {
909
1114
  },
910
1115
  }))
911
1116
  .actions(self => ({
1117
+ /**
1118
+ * #action
1119
+ */
1120
+ setHeaderHeight(arg) {
1121
+ self.headerHeight = arg;
1122
+ },
912
1123
  /**
913
1124
  * #action
914
1125
  */
915
1126
  reset() {
916
- transaction(() => {
917
- self.setData({ tree: '', msa: '' });
918
- self.setScrollY(0);
919
- self.setScrollX(0);
920
- self.setCurrentAlignment(0);
921
- self.setTreeFilehandle(undefined);
922
- self.setMSAFilehandle(undefined);
923
- });
1127
+ self.setData({ tree: '', msa: '' });
1128
+ self.setError(undefined);
1129
+ self.setScrollY(0);
1130
+ self.setScrollX(0);
1131
+ self.setCurrentAlignment(0);
1132
+ self.setTreeFilehandle(undefined);
1133
+ self.setMSAFilehandle(undefined);
924
1134
  },
925
1135
  /**
926
1136
  * #action
@@ -955,7 +1165,7 @@ function stateModelFactory() {
955
1165
  },
956
1166
  afterCreate() {
957
1167
  addDisposer(self, autorun(() => {
958
- for (const key of self.tidyTypes.keys()) {
1168
+ for (const key of self.tidyInterProAnnotationTypes.keys()) {
959
1169
  this.initFilter(key);
960
1170
  }
961
1171
  }));
@@ -999,9 +1209,11 @@ function stateModelFactory() {
999
1209
  if (msaFilehandle) {
1000
1210
  try {
1001
1211
  self.setLoadingMSA(true);
1002
- const res = await openLocation(msaFilehandle).readFile('utf8');
1212
+ const res = await openLocation(msaFilehandle).readFile();
1213
+ const buf = isGzip(res) ? ungzip(res) : res;
1214
+ const txt = new TextDecoder('utf8').decode(buf);
1003
1215
  transaction(() => {
1004
- self.setMSA(res);
1216
+ self.setMSA(txt);
1005
1217
  if (msaFilehandle.locationType === 'BlobLocation') {
1006
1218
  // clear filehandle after loading if from a local file
1007
1219
  self.setMSAFilehandle(undefined);
@@ -1017,6 +1229,17 @@ function stateModelFactory() {
1017
1229
  }
1018
1230
  }
1019
1231
  }));
1232
+ // force colStats not to go stale
1233
+ // xref solution https://github.com/mobxjs/mobx/issues/266#issuecomment-222007278
1234
+ // xref problem https://github.com/GMOD/react-msaview/issues/75
1235
+ addDisposer(self, autorun(() => {
1236
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1237
+ self.colStats;
1238
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1239
+ self.colStatsSums;
1240
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1241
+ self.columns;
1242
+ }));
1020
1243
  // autorun synchronizes treeWidth with treeAreaWidth
1021
1244
  addDisposer(self, autorun(async () => {
1022
1245
  if (self.treeWidthMatchesArea) {