react-msaview 3.2.0 → 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 (154) hide show
  1. package/bundle/index.js +12 -12
  2. package/dist/colorSchemes.js +2 -2
  3. package/dist/colorSchemes.js.map +1 -1
  4. package/dist/components/Loading.js +3 -1
  5. package/dist/components/Loading.js.map +1 -1
  6. package/dist/components/ResizeHandles.js +6 -2
  7. package/dist/components/ResizeHandles.js.map +1 -1
  8. package/dist/components/SequenceTextArea.js +9 -3
  9. package/dist/components/SequenceTextArea.js.map +1 -1
  10. package/dist/components/TextTrack.js +1 -1
  11. package/dist/components/TextTrack.js.map +1 -1
  12. package/dist/components/Track.js +6 -2
  13. package/dist/components/Track.js.map +1 -1
  14. package/dist/components/VerticalScrollbar.js +5 -1
  15. package/dist/components/VerticalScrollbar.js.map +1 -1
  16. package/dist/components/dialogs/AboutDialog.js +3 -1
  17. package/dist/components/dialogs/AboutDialog.js.map +1 -1
  18. package/dist/components/dialogs/AddTrackDialog.d.ts +2 -2
  19. package/dist/components/dialogs/AddTrackDialog.js +8 -3
  20. package/dist/components/dialogs/AddTrackDialog.js.map +1 -1
  21. package/dist/components/dialogs/DomainDialog.js +6 -2
  22. package/dist/components/dialogs/DomainDialog.js.map +1 -1
  23. package/dist/components/dialogs/ExportSVGDialog.js +29 -17
  24. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
  25. package/dist/components/dialogs/FeatureDialog.js +8 -4
  26. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  27. package/dist/components/dialogs/InterProScanDialog.js +23 -9
  28. package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
  29. package/dist/components/dialogs/MetadataDialog.js +3 -1
  30. package/dist/components/dialogs/MetadataDialog.js.map +1 -1
  31. package/dist/components/dialogs/SettingsDialog.js +61 -23
  32. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  33. package/dist/components/dialogs/TracklistDialog.d.ts +2 -2
  34. package/dist/components/dialogs/TracklistDialog.js +8 -3
  35. package/dist/components/dialogs/TracklistDialog.js.map +1 -1
  36. package/dist/components/dialogs/UserProvidedDomainsDialog.js +10 -4
  37. package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -1
  38. package/dist/components/header/Header.js +3 -1
  39. package/dist/components/header/Header.js.map +1 -1
  40. package/dist/components/header/HeaderInfoArea.js +5 -2
  41. package/dist/components/header/HeaderInfoArea.js.map +1 -1
  42. package/dist/components/header/HeaderMenu.js +12 -4
  43. package/dist/components/header/HeaderMenu.js.map +1 -1
  44. package/dist/components/header/HeaderMenuExtra.js +34 -16
  45. package/dist/components/header/HeaderMenuExtra.js.map +1 -1
  46. package/dist/components/header/ZoomControls.js +18 -6
  47. package/dist/components/header/ZoomControls.js.map +1 -1
  48. package/dist/components/import/ImportForm.d.ts +2 -2
  49. package/dist/components/import/ImportForm.js +15 -2
  50. package/dist/components/import/ImportForm.js.map +1 -1
  51. package/dist/components/import/ImportFormExamples.js +44 -31
  52. package/dist/components/import/ImportFormExamples.js.map +1 -1
  53. package/dist/components/minimap/Minimap.js +12 -4
  54. package/dist/components/minimap/Minimap.js.map +1 -1
  55. package/dist/components/msa/MSACanvasBlock.js +5 -3
  56. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  57. package/dist/components/msa/MSAMouseoverCanvas.d.ts +1 -1
  58. package/dist/components/msa/MSAMouseoverCanvas.js +1 -1
  59. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  60. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +2 -2
  61. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  62. package/dist/components/msa/renderMSABlock.js +4 -4
  63. package/dist/components/msa/renderMSABlock.js.map +1 -1
  64. package/dist/components/msa/renderMSAMouseover.js +3 -3
  65. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  66. package/dist/components/tree/TreeBranchMenu.js +6 -3
  67. package/dist/components/tree/TreeBranchMenu.js.map +1 -1
  68. package/dist/components/tree/TreeCanvasBlock.js +11 -4
  69. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  70. package/dist/components/tree/TreeNodeMenu.js +1 -1
  71. package/dist/components/tree/TreeNodeMenu.js.map +1 -1
  72. package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +2 -2
  73. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +5 -2
  74. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  75. package/dist/components/util.js +0 -3
  76. package/dist/components/util.js.map +1 -1
  77. package/dist/ggplotPalettes.js.map +1 -1
  78. package/dist/launchInterProScan.js +4 -4
  79. package/dist/launchInterProScan.js.map +1 -1
  80. package/dist/model/DialogQueue.js +0 -1
  81. package/dist/model/DialogQueue.js.map +1 -1
  82. package/dist/model.d.ts +57 -22
  83. package/dist/model.js +87 -50
  84. package/dist/model.js.map +1 -1
  85. package/dist/parseGFF.js +8 -6
  86. package/dist/parseGFF.js.map +1 -1
  87. package/dist/parseNewick.js +0 -1
  88. package/dist/parseNewick.js.map +1 -1
  89. package/dist/parsers/ClustalMSA.d.ts +1 -1
  90. package/dist/parsers/ClustalMSA.js.map +1 -1
  91. package/dist/parsers/FastaMSA.js +3 -3
  92. package/dist/parsers/FastaMSA.js.map +1 -1
  93. package/dist/parsers/StockholmMSA.d.ts +6 -6
  94. package/dist/parsers/StockholmMSA.js +4 -4
  95. package/dist/parsers/StockholmMSA.js.map +1 -1
  96. package/dist/renderToSvg.js +3 -6
  97. package/dist/renderToSvg.js.map +1 -1
  98. package/dist/rowCoordinateCalculations.d.ts +2 -0
  99. package/dist/rowCoordinateCalculations.js +26 -0
  100. package/dist/rowCoordinateCalculations.js.map +1 -0
  101. package/dist/rowCoordinateCalculations.test.d.ts +1 -0
  102. package/dist/rowCoordinateCalculations.test.js +18 -0
  103. package/dist/rowCoordinateCalculations.test.js.map +1 -0
  104. package/dist/version.d.ts +1 -1
  105. package/dist/version.js +1 -1
  106. package/package.json +7 -3
  107. package/src/colorSchemes.ts +4 -4
  108. package/src/components/Loading.tsx +7 -1
  109. package/src/components/ResizeHandles.tsx +6 -2
  110. package/src/components/SequenceTextArea.tsx +10 -4
  111. package/src/components/TextTrack.tsx +2 -2
  112. package/src/components/Track.tsx +8 -4
  113. package/src/components/VerticalScrollbar.tsx +6 -2
  114. package/src/components/dialogs/AboutDialog.tsx +7 -1
  115. package/src/components/dialogs/AddTrackDialog.tsx +13 -3
  116. package/src/components/dialogs/DomainDialog.tsx +9 -2
  117. package/src/components/dialogs/ExportSVGDialog.tsx +36 -17
  118. package/src/components/dialogs/FeatureDialog.tsx +7 -5
  119. package/src/components/dialogs/InterProScanDialog.tsx +20 -10
  120. package/src/components/dialogs/MetadataDialog.tsx +8 -1
  121. package/src/components/dialogs/SettingsDialog.tsx +76 -32
  122. package/src/components/dialogs/TracklistDialog.tsx +17 -3
  123. package/src/components/dialogs/UserProvidedDomainsDialog.tsx +11 -5
  124. package/src/components/header/Header.tsx +3 -1
  125. package/src/components/header/HeaderInfoArea.tsx +3 -2
  126. package/src/components/header/HeaderMenu.tsx +12 -7
  127. package/src/components/header/HeaderMenuExtra.tsx +28 -16
  128. package/src/components/header/ZoomControls.tsx +22 -6
  129. package/src/components/import/ImportForm.tsx +14 -2
  130. package/src/components/import/ImportFormExamples.tsx +59 -48
  131. package/src/components/minimap/Minimap.tsx +21 -9
  132. package/src/components/msa/MSACanvasBlock.tsx +5 -3
  133. package/src/components/msa/MSAMouseoverCanvas.tsx +5 -1
  134. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +4 -4
  135. package/src/components/msa/renderMSABlock.ts +10 -10
  136. package/src/components/msa/renderMSAMouseover.ts +3 -3
  137. package/src/components/tree/TreeBranchMenu.tsx +5 -3
  138. package/src/components/tree/TreeCanvasBlock.tsx +11 -4
  139. package/src/components/tree/TreeNodeMenu.tsx +1 -1
  140. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +11 -2
  141. package/src/components/util.ts +1 -4
  142. package/src/ggplotPalettes.ts +1 -1
  143. package/src/launchInterProScan.ts +5 -5
  144. package/src/model/DialogQueue.ts +0 -1
  145. package/src/model.ts +99 -56
  146. package/src/parseGFF.ts +13 -11
  147. package/src/parseNewick.ts +3 -3
  148. package/src/parsers/ClustalMSA.ts +2 -2
  149. package/src/parsers/FastaMSA.ts +4 -4
  150. package/src/parsers/StockholmMSA.ts +10 -10
  151. package/src/renderToSvg.tsx +1 -2
  152. package/src/rowCoordinateCalculations.test.ts +19 -0
  153. package/src/rowCoordinateCalculations.ts +26 -0
  154. package/src/version.ts +1 -1
package/src/model.ts CHANGED
@@ -53,6 +53,10 @@ import { DialogQueueSessionMixin } from './model/DialogQueue'
53
53
  import { TreeF } from './model/treeModel'
54
54
  import { MSAModelF } from './model/msaModel'
55
55
  import type { InterProScanResults } from './launchInterProScan'
56
+ import {
57
+ mouseOverCoordToGlobalCoord,
58
+ globalCoordToRowSpecificCoord,
59
+ } from './rowCoordinateCalculations'
56
60
 
57
61
  export interface Accession {
58
62
  accession: string
@@ -72,7 +76,6 @@ export interface TextTrackModel extends BasicTrackModel {
72
76
  }
73
77
 
74
78
  export interface ITextTrack {
75
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
79
  ReactComponent: React.FC<any>
77
80
  model: TextTrackModel
78
81
  }
@@ -514,6 +517,12 @@ function stateModelFactory() {
514
517
  }))
515
518
 
516
519
  .views(self => ({
520
+ /**
521
+ * #getter
522
+ */
523
+ get realAllowedGappyness() {
524
+ return self.hideGaps ? self.allowedGappyness : 100
525
+ },
517
526
  /**
518
527
  * #getter
519
528
  */
@@ -548,7 +557,7 @@ function stateModelFactory() {
548
557
  * #getter
549
558
  */
550
559
  get colorScheme() {
551
- return colorSchemes[self.colorSchemeName]
560
+ return colorSchemes[self.colorSchemeName]!
552
561
  },
553
562
 
554
563
  /**
@@ -588,7 +597,7 @@ function stateModelFactory() {
588
597
  /**
589
598
  * #getter
590
599
  */
591
- get menuItems() {
600
+ menuItems() {
592
601
  return []
593
602
  },
594
603
  /**
@@ -653,6 +662,8 @@ function stateModelFactory() {
653
662
  */
654
663
  get root() {
655
664
  let hier = hierarchy(this.tree, d => d.branchset)
665
+ // todo: investigate whether needed, typescript says branchset always true
666
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
656
667
  .sum(d => (d.branchset ? 0 : 1))
657
668
  .sort((a, b) => ascending(a.data.length || 1, b.data.length || 1))
658
669
 
@@ -666,7 +677,9 @@ function stateModelFactory() {
666
677
  ;[...self.collapsed, ...self.collapsedLeaves]
667
678
  .map(collapsedId => hier.find(node => node.data.id === collapsedId))
668
679
  .filter(notEmpty)
669
- .map(node => collapse(node))
680
+ .map(node => {
681
+ collapse(node)
682
+ })
670
683
 
671
684
  return hier
672
685
  },
@@ -689,25 +702,34 @@ function stateModelFactory() {
689
702
  * #getter
690
703
  */
691
704
  get blanks() {
692
- const { allowedGappyness } = self
705
+ const { hideGaps, realAllowedGappyness } = self
693
706
  const blanks = []
694
- const strs = this.leaves
695
- .map(leaf => this.MSA?.getRow(leaf.data.name))
696
- .filter((item): item is string => !!item)
697
-
698
- for (let i = 0; i < strs[0]?.length; i++) {
699
- let counter = 0
700
- for (const str of strs) {
701
- if (str[i] === '-') {
702
- counter++
707
+ if (hideGaps) {
708
+ const strs = this.leaves
709
+ .map(leaf => this.MSA?.getRow(leaf.data.name))
710
+ .filter((item): item is string => !!item)
711
+ if (strs.length) {
712
+ for (let i = 0; i < strs[0]!.length; i++) {
713
+ let counter = 0
714
+ for (const str of strs) {
715
+ if (str[i] === '-') {
716
+ counter++
717
+ }
718
+ }
719
+ if (counter / strs.length >= realAllowedGappyness / 100) {
720
+ blanks.push(i)
721
+ }
703
722
  }
704
723
  }
705
- if (counter / strs.length >= allowedGappyness / 100) {
706
- blanks.push(i)
707
- }
708
724
  }
709
725
  return blanks
710
726
  },
727
+ /**
728
+ * #getter
729
+ */
730
+ get blanksSet() {
731
+ return new Set(this.blanks)
732
+ },
711
733
  /**
712
734
  * #getter
713
735
  */
@@ -717,13 +739,20 @@ function stateModelFactory() {
717
739
  .map(leaf => [leaf.data.name, MSA?.getRow(leaf.data.name)] as const)
718
740
  .filter((f): f is [string, string] => !!f[1])
719
741
  },
742
+
743
+ /**
744
+ * #getter
745
+ */
746
+ get rowMap() {
747
+ return new Map(this.rows)
748
+ },
720
749
  /**
721
750
  * #getter
722
751
  */
723
752
  get columns() {
724
753
  return Object.fromEntries(
725
754
  this.rows.map(
726
- (row, index) => [row[0], this.columns2d[index]] as const,
755
+ (row, index) => [row[0], this.columns2d[index]!] as const,
727
756
  ),
728
757
  )
729
758
  },
@@ -748,10 +777,11 @@ function stateModelFactory() {
748
777
  for (const column of columns) {
749
778
  for (let j = 0; j < column.length; j++) {
750
779
  const l = r[j] || {}
751
- if (!l[column[j]]) {
752
- l[column[j]] = 0
780
+ const cj = column[j]!
781
+ if (!l[cj]) {
782
+ l[cj] = 0
753
783
  }
754
- l[column[j]]++
784
+ l[cj]++
755
785
  r[j] = l
756
786
  }
757
787
  }
@@ -843,7 +873,7 @@ function stateModelFactory() {
843
873
  const ret = []
844
874
  for (const by of self.blocksY) {
845
875
  for (const bx of self.blocksX) {
846
- ret.push([bx, by])
876
+ ret.push([bx, by] as const)
847
877
  }
848
878
  }
849
879
  return ret
@@ -1013,7 +1043,7 @@ function stateModelFactory() {
1013
1043
  */
1014
1044
  get conservation() {
1015
1045
  if (self.columns2d.length) {
1016
- for (let i = 0; i < self.columns2d[0].length; i++) {
1046
+ for (let i = 0; i < self.columns2d[0]!.length; i++) {
1017
1047
  const col = []
1018
1048
  for (const column of self.columns2d) {
1019
1049
  col.push(column[i])
@@ -1060,28 +1090,39 @@ function stateModelFactory() {
1060
1090
  return self.msaAreaWidth < self.totalWidth
1061
1091
  },
1062
1092
 
1093
+ /**
1094
+ * #getter
1095
+ */
1096
+ get rowNamesSet() {
1097
+ return new Map(self.rowNames.map((r, idx) => [r, idx]))
1098
+ },
1099
+
1063
1100
  /**
1064
1101
  * #method
1065
- * return a row-specific sequence coordinate, skipping gaps, given a global
1066
- * coordinate
1102
+ * return a row-specific letter, or undefined if gap
1067
1103
  */
1068
- globalCoordToRowSpecificSeqCoord(rowName: string, position: number) {
1069
- const { rowNames, rows } = self
1070
- const index = rowNames.indexOf(rowName)
1071
- if (index !== -1 && rows[index]) {
1072
- const row = rows[index][1]
1104
+ mouseOverCoordToRowLetter(rowName: string, position: number) {
1105
+ const { rowMap, blanks } = self
1106
+ return rowMap.get(rowName)?.[
1107
+ mouseOverCoordToGlobalCoord(blanks, position)
1108
+ ]
1109
+ },
1073
1110
 
1074
- let k = 0
1075
- for (let i = 0; i < position; i++) {
1076
- if (row[i] !== '-') {
1077
- k++
1078
- } else if (k >= position) {
1079
- break
1080
- }
1081
- }
1082
- return k
1111
+ /**
1112
+ * #method
1113
+ * return a row-specific sequence coordinate, skipping gaps, given a
1114
+ * global coordinate
1115
+ */
1116
+ mouseOverCoordToGapRemovedRowCoord(rowName: string, position: number) {
1117
+ const { rowMap, blanks } = self
1118
+ const seq = rowMap.get(rowName)
1119
+ if (seq !== undefined) {
1120
+ const pos2 = mouseOverCoordToGlobalCoord(blanks, position)
1121
+ const pos1 = globalCoordToRowSpecificCoord(seq, pos2)
1122
+ return seq[pos1] === '-' || !seq[pos1] ? undefined : pos1
1123
+ } else {
1124
+ return undefined
1083
1125
  }
1084
- return 0
1085
1126
  },
1086
1127
 
1087
1128
  /**
@@ -1132,19 +1173,17 @@ function stateModelFactory() {
1132
1173
  /**
1133
1174
  * #getter
1134
1175
  */
1135
- get tidyTypes() {
1176
+ get tidyInterProAnnotationTypes() {
1136
1177
  const types = new Map<string, Accession>()
1137
- if (this.tidyAnnotations) {
1138
- for (const { name, accession, description } of this.tidyAnnotations) {
1139
- types.set(accession, { name, accession, description })
1140
- }
1178
+ for (const annot of this.tidyInterProAnnotations) {
1179
+ types.set(annot.accession, annot)
1141
1180
  }
1142
1181
  return types
1143
1182
  },
1144
1183
  /**
1145
1184
  * #getter
1146
1185
  */
1147
- get tidyAnnotations() {
1186
+ get tidyInterProAnnotations() {
1148
1187
  const ret = []
1149
1188
  const { interProAnnotations } = self
1150
1189
  if (interProAnnotations) {
@@ -1172,16 +1211,16 @@ function stateModelFactory() {
1172
1211
  /**
1173
1212
  * #getter
1174
1213
  */
1175
- get tidyFilteredAnnotations() {
1176
- return this.tidyAnnotations.filter(r =>
1214
+ get tidyFilteredInterProAnnotations() {
1215
+ return this.tidyInterProAnnotations.filter(r =>
1177
1216
  self.featureFilters.get(r.accession),
1178
1217
  )
1179
1218
  },
1180
1219
  /**
1181
1220
  * #getter
1182
1221
  */
1183
- get tidyFilteredGatheredAnnotations() {
1184
- return groupBy(this.tidyFilteredAnnotations, r => r.id)
1222
+ get tidyFilteredGatheredInterProAnnotations() {
1223
+ return groupBy(this.tidyFilteredInterProAnnotations, r => r.id)
1185
1224
  },
1186
1225
  }))
1187
1226
  .views(self => ({
@@ -1203,12 +1242,12 @@ function stateModelFactory() {
1203
1242
  * #getter
1204
1243
  */
1205
1244
  get fillPalette() {
1206
- const arr = [...self.tidyTypes.keys()]
1245
+ const arr = [...self.tidyInterProAnnotationTypes.keys()]
1207
1246
  let i = 0
1208
1247
  const map = {} as Record<string, string>
1209
1248
  for (const key of arr) {
1210
1249
  const k = Math.min(arr.length - 1, palettes.length - 1)
1211
- map[key] = palettes[k][i]
1250
+ map[key] = palettes[k]![i]!
1212
1251
  i++
1213
1252
  }
1214
1253
  return map
@@ -1285,7 +1324,7 @@ function stateModelFactory() {
1285
1324
  addDisposer(
1286
1325
  self,
1287
1326
  autorun(() => {
1288
- for (const key of self.tidyTypes.keys()) {
1327
+ for (const key of self.tidyInterProAnnotationTypes.keys()) {
1289
1328
  this.initFilter(key)
1290
1329
  }
1291
1330
  }),
@@ -1361,17 +1400,21 @@ function stateModelFactory() {
1361
1400
  }),
1362
1401
  )
1363
1402
 
1403
+ // force colStats not to go stale
1404
+ // xref solution https://github.com/mobxjs/mobx/issues/266#issuecomment-222007278
1405
+ // xref problem https://github.com/GMOD/react-msaview/issues/75
1364
1406
  addDisposer(
1365
1407
  self,
1366
1408
  autorun(() => {
1367
- // force colStats not to go stale,
1368
- // xref solution https://github.com/mobxjs/mobx/issues/266#issuecomment-222007278
1369
- // xref problem https://github.com/GMOD/react-msaview/issues/75
1409
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1370
1410
  self.colStats
1411
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1371
1412
  self.colStatsSums
1413
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
1372
1414
  self.columns
1373
1415
  }),
1374
1416
  )
1417
+
1375
1418
  // autorun synchronizes treeWidth with treeAreaWidth
1376
1419
  addDisposer(
1377
1420
  self,
package/src/parseGFF.ts CHANGED
@@ -8,23 +8,25 @@ export function parseGFF(str?: string) {
8
8
  f.split('\t')
9
9
 
10
10
  return {
11
- seq_id,
12
- source,
13
- type,
14
- start: +start,
15
- end: +end,
16
- score: +score,
17
- strand,
18
- phase,
11
+ seq_id: seq_id!,
12
+ source: source!,
13
+ type: type!,
14
+ start: +start!,
15
+ end: +end!,
16
+ score: +score!,
17
+ strand: strand!,
18
+ phase: phase!,
19
19
  ...Object.fromEntries(
20
- col9
20
+ col9!
21
21
  .split(';')
22
22
  .map(f => f.trim())
23
23
  .filter(f => !!f)
24
24
  .map(f => f.split('='))
25
25
  .map(([key, val]) => [
26
- key.trim(),
27
- decodeURIComponent(val).trim().split(',').join(' '),
26
+ key!.trim(),
27
+ val
28
+ ? decodeURIComponent(val).trim().split(',').join(' ')
29
+ : undefined,
28
30
  ]),
29
31
  ),
30
32
  }
@@ -59,11 +59,11 @@
59
59
  */
60
60
  export default function parse(s: string) {
61
61
  const ancestors = []
62
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+
63
63
  let tree = {} as Record<string, any>
64
64
  const tokens = s.split(/\s*(;|\(|\)|,|:)\s*/)
65
65
  for (let i = 0; i < tokens.length; i++) {
66
- const token = tokens[i]
66
+ const token = tokens[i]!
67
67
  const subtree = {}
68
68
  switch (token) {
69
69
  case '(': // new branchset
@@ -81,7 +81,7 @@ export default function parse(s: string) {
81
81
  case ':': // optional length next
82
82
  break
83
83
  default: {
84
- const x = tokens[i - 1]
84
+ const x = tokens[i - 1]!
85
85
  if (x === ')' || x === '(' || x === ',') {
86
86
  tree.name = token
87
87
  } else if (x === ':') {
@@ -11,12 +11,12 @@ export default class ClustalMSA {
11
11
  return this.MSA
12
12
  }
13
13
 
14
- getRow(name: string) {
14
+ getRow(name: string): string {
15
15
  return this.MSA.alns.find(aln => aln.id === name)?.seq || ''
16
16
  }
17
17
 
18
18
  getWidth() {
19
- return this.MSA.alns[0].seq.length
19
+ return this.MSA.alns[0]!.seq.length
20
20
  }
21
21
 
22
22
  getRowData() {
@@ -6,7 +6,7 @@ function parseSmallFasta(text: string) {
6
6
  .filter(t => /\S/.test(t))
7
7
  .map(entryText => {
8
8
  const [defLine, ...seqLines] = entryText.split('\n')
9
- const [id, ...description] = defLine.split(' ')
9
+ const [id, ...description] = defLine!.split(' ')
10
10
  const descriptionStr = description.join(' ')
11
11
  const seqLinesStr = seqLines.join('')
12
12
  const sequence = seqLinesStr.replaceAll(/\s/g, '')
@@ -18,7 +18,7 @@ export default class FastaMSA {
18
18
  constructor(text: string) {
19
19
  this.MSA = {
20
20
  seqdata: Object.fromEntries(
21
- parseSmallFasta(text).map(m => [`${m.id}`, m.sequence]),
21
+ parseSmallFasta(text).map(m => [m.id, m.sequence]),
22
22
  ),
23
23
  }
24
24
  }
@@ -36,11 +36,11 @@ export default class FastaMSA {
36
36
  }
37
37
 
38
38
  getRow(name: string) {
39
- return this.MSA?.seqdata[name] || ''
39
+ return this.MSA.seqdata[name] || ''
40
40
  }
41
41
 
42
42
  getWidth() {
43
- const name = Object.keys(this.MSA?.seqdata)[0]
43
+ const name = Object.keys(this.MSA.seqdata)[0]!
44
44
  return this.getRow(name).length
45
45
  }
46
46
 
@@ -7,9 +7,9 @@ interface StockholmEntry {
7
7
  DE?: string[]
8
8
  NH?: string[]
9
9
  }
10
- gs: {
10
+ gs?: {
11
11
  AC: Record<string, string>
12
- DR: Record<string, string>
12
+ DR?: Record<string, string>
13
13
  }
14
14
  gc?: {
15
15
  SS_cons?: string
@@ -33,11 +33,11 @@ export default class StockholmMSA {
33
33
  }
34
34
 
35
35
  getRow(name: string) {
36
- return this.MSA?.seqdata[name] || ''
36
+ return this.MSA.seqdata[name] || ''
37
37
  }
38
38
 
39
39
  getWidth() {
40
- const name = Object.keys(this.MSA?.seqdata)[0]
40
+ const name = Object.keys(this.MSA.seqdata)[0]!
41
41
  return this.getRow(name).length
42
42
  }
43
43
 
@@ -56,7 +56,7 @@ export default class StockholmMSA {
56
56
  getRowData(rowName: string) {
57
57
  return {
58
58
  name: rowName,
59
- accession: this.MSA.gs?.AC?.[rowName],
59
+ accession: this.MSA.gs?.AC[rowName],
60
60
  dbxref: this.MSA.gs?.DR?.[rowName],
61
61
  }
62
62
  }
@@ -74,10 +74,10 @@ export default class StockholmMSA {
74
74
  .map(([id, dr]) => [id, pdbRegex.exec(dr)] as const)
75
75
  .filter((item): item is [string, RegExpExecArray] => !!item[1])
76
76
  .map(([id, match]) => {
77
- const pdb = match[1].toLowerCase()
78
- const chain = match[2]
79
- const startPos = +match[3]
80
- const endPos = +match[4]
77
+ const pdb = match[1]!.toLowerCase()
78
+ const chain = match[2]!
79
+ const startPos = +match[3]!
80
+ const endPos = +match[4]!
81
81
  return { id, pdb, chain, startPos, endPos }
82
82
  })
83
83
 
@@ -93,7 +93,7 @@ export default class StockholmMSA {
93
93
  }
94
94
 
95
95
  getTree(): NodeWithIds {
96
- const tree = this.MSA?.gf?.NH?.[0]
96
+ const tree = this.MSA.gf.NH?.[0]
97
97
  return tree
98
98
  ? generateNodeIds(parseNewick(tree))
99
99
  : {
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react-refresh/only-export-components */
1
2
  import React from 'react'
2
3
  import { createRoot } from 'react-dom/client'
3
4
  import { when } from 'mobx'
@@ -153,13 +154,11 @@ function CoreRendering({
153
154
 
154
155
  <g
155
156
  clipPath={`url(#${clipId1})`}
156
- /* eslint-disable-next-line react/no-danger */
157
157
  dangerouslySetInnerHTML={{ __html: ctx1.getSvg().innerHTML }}
158
158
  />
159
159
  <g
160
160
  clipPath={`url(#${clipId2})`}
161
161
  transform={`translate(${treeAreaWidth} 0)`}
162
- /* eslint-disable-next-line react/no-danger */
163
162
  dangerouslySetInnerHTML={{ __html: ctx2.getSvg().innerHTML }}
164
163
  />
165
164
  </>
@@ -0,0 +1,19 @@
1
+ import { expect, test } from 'vitest'
2
+ import { mouseOverCoordToGlobalCoord } from './rowCoordinateCalculations'
3
+ test('blanks3', () => {
4
+ const blanks = [2, 5, 8]
5
+ ;(
6
+ [
7
+ [0, 0],
8
+ [1, 1],
9
+ [2, 3],
10
+ [3, 4],
11
+ [4, 6],
12
+ [5, 7],
13
+ [6, 9],
14
+ [7, 10],
15
+ ] as const
16
+ ).forEach(r => {
17
+ expect(mouseOverCoordToGlobalCoord(blanks, r[0])).toBe(r[1])
18
+ })
19
+ })
@@ -0,0 +1,26 @@
1
+ export function mouseOverCoordToGlobalCoord(blanks: number[], pos: number) {
2
+ let i = 0 // 'mouse over coord'
3
+ let j = 0 // 'position in blanks array'
4
+ let k = 0 // 'global coord'/return value
5
+
6
+ for (; i < pos; i++, k++) {
7
+ // skip multiple gaps in a row
8
+ while (j < blanks.length && blanks[j]! - 1 === k) {
9
+ j++
10
+ k++
11
+ }
12
+ }
13
+ return k
14
+ }
15
+
16
+ export function globalCoordToRowSpecificCoord(seq: string, pos: number) {
17
+ let k = 0
18
+ for (let i = 0; i < pos; i++) {
19
+ if (seq[i] !== '-') {
20
+ k++
21
+ } else if (k >= pos) {
22
+ break
23
+ }
24
+ }
25
+ return k
26
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '3.2.0'
1
+ export const version = '3.2.1'