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
@@ -9,7 +9,7 @@ import type { MsaViewModel } from '../../model'
9
9
  import { load } from './util'
10
10
  import ImportFormExamples from './ImportFormExamples'
11
11
 
12
- export default observer(function ({ model }: { model: MsaViewModel }) {
12
+ const ImportForm = observer(function ({ model }: { model: MsaViewModel }) {
13
13
  const [msaFile, setMsaFile] = useState<FileLocation>()
14
14
  const [treeFile, setTreeFile] = useState<FileLocation>()
15
15
  const { error } = model
@@ -44,7 +44,17 @@ export default observer(function ({ model }: { model: MsaViewModel }) {
44
44
 
45
45
  <Grid item>
46
46
  <Button
47
- onClick={() => load(model, msaFile, treeFile)}
47
+ onClick={() => {
48
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
49
+ ;(async () => {
50
+ try {
51
+ await load(model, msaFile, treeFile)
52
+ } catch (e) {
53
+ console.error(e)
54
+ model.setError(e)
55
+ }
56
+ })()
57
+ }}
48
58
  variant="contained"
49
59
  color="primary"
50
60
  disabled={!msaFile && !treeFile}
@@ -61,3 +71,5 @@ export default observer(function ({ model }: { model: MsaViewModel }) {
61
71
  </Container>
62
72
  )
63
73
  })
74
+
75
+ export default ImportForm
@@ -37,16 +37,41 @@ const ImportFormExamples = observer(function ({
37
37
  }: {
38
38
  model: MsaViewModel
39
39
  }) {
40
+ function l2(uri1?: string, uri2?: string) {
41
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
42
+ ;(async () => {
43
+ try {
44
+ await load(
45
+ model,
46
+ uri1
47
+ ? {
48
+ uri: uri1,
49
+ locationType: 'UriLocation',
50
+ }
51
+ : undefined,
52
+ uri2
53
+ ? {
54
+ uri: uri2,
55
+ locationType: 'UriLocation',
56
+ }
57
+ : undefined,
58
+ )
59
+ } catch (e) {
60
+ console.error(e)
61
+ model.setError(e)
62
+ }
63
+ })()
64
+ }
40
65
  return (
41
66
  <ul>
42
67
  <ListItem
43
68
  model={model}
44
- onClick={() =>
45
- load(model, undefined, {
46
- uri: 'https://jbrowse.org/genomes/newicktrees/sarscov2phylo.pub.ft.nh',
47
- locationType: 'UriLocation',
48
- })
49
- }
69
+ onClick={() => {
70
+ l2(
71
+ undefined,
72
+ 'https://jbrowse.org/genomes/newicktrees/sarscov2phylo.pub.ft.nh',
73
+ )
74
+ }}
50
75
  >
51
76
  230k COVID-19 samples (tree only)
52
77
  </ListItem>
@@ -68,74 +93,60 @@ const ImportFormExamples = observer(function ({
68
93
  </ListItem>
69
94
  <ListItem
70
95
  model={model}
71
- onClick={() =>
72
- load(model, {
73
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/pfam-cov2.stock',
74
- locationType: 'UriLocation',
75
- })
76
- }
96
+ onClick={() => {
97
+ l2(
98
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/pfam-cov2.stock',
99
+ )
100
+ }}
77
101
  >
78
102
  PFAM SARS-CoV2 multi-stockholm
79
103
  </ListItem>
80
104
  <ListItem
81
105
  model={model}
82
- onClick={() =>
83
- load(model, {
84
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/Lysine.stock',
85
- locationType: 'UriLocation',
86
- })
87
- }
106
+ onClick={() => {
107
+ l2(
108
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/Lysine.stock',
109
+ )
110
+ }}
88
111
  >
89
112
  Lysine stockholm file
90
113
  </ListItem>
91
114
  <ListItem
92
115
  model={model}
93
- onClick={() =>
94
- load(model, {
95
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/PF01601_full.txt',
96
- locationType: 'UriLocation',
97
- })
98
- }
116
+ onClick={() => {
117
+ l2(
118
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/PF01601_full.txt',
119
+ )
120
+ }}
99
121
  >
100
122
  PF01601 stockholm file (SARS-CoV2 spike protein)
101
123
  </ListItem>
102
124
  <ListItem
103
125
  model={model}
104
- onClick={() =>
105
- load(model, {
106
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/europe_covid.fa',
107
- locationType: 'UriLocation',
108
- })
109
- }
126
+ onClick={() => {
127
+ l2(
128
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/europe_covid.fa',
129
+ )
130
+ }}
110
131
  >
111
132
  Europe COVID full genomes (LR883044.1 and 199 other sequences)
112
133
  </ListItem>
113
134
  <ListItem
114
135
  model={model}
115
- onClick={() =>
116
- load(
117
- model,
118
- {
119
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/rhv_test-only.aligned_with_mafft_auto.fa',
120
- locationType: 'UriLocation',
121
- },
122
- {
123
- uri: 'https://jbrowse.org/genomes/multiple_sequence_alignments/rhv_test-only.aligned_with_mafft_auto.nh',
124
- locationType: 'UriLocation',
125
- },
136
+ onClick={() => {
137
+ l2(
138
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/rhv_test-only.aligned_with_mafft_auto.fa',
139
+ 'https://jbrowse.org/genomes/multiple_sequence_alignments/rhv_test-only.aligned_with_mafft_auto.nh',
126
140
  )
127
- }
141
+ }}
128
142
  >
129
143
  MAFFT+VeryFastTree(17.9k samples)
130
144
  </ListItem>
131
145
  <ListItem
132
146
  model={model}
133
- onClick={() =>
134
- load(model, {
135
- uri: 'https://jbrowse.org/demos/ttc39a.mfa',
136
- locationType: 'UriLocation',
137
- })
138
- }
147
+ onClick={() => {
148
+ l2('https://jbrowse.org/demos/ttc39a.mfa')
149
+ }}
139
150
  >
140
151
  Human BLAST results mfa
141
152
  </ListItem>
@@ -2,13 +2,15 @@ import React, { useEffect, useRef, useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import type { MsaViewModel } from '../../model'
4
4
 
5
+ interface ClickCoord {
6
+ clientX: number
7
+ scrollX: number
8
+ }
9
+
5
10
  const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
6
- const [mouseDown, setMouseDown] = useState<{
7
- clientX: number
8
- scrollX: number
9
- }>()
10
- const scheduled = useRef(false)
11
+ const [mouseDown, setMouseDown] = useState<ClickCoord>()
11
12
  const [hovered, setHovered] = useState(false)
13
+ const scheduled = useRef(false)
12
14
  const { scrollX, msaAreaWidth, minimapHeight, colWidth, numColumns } = model
13
15
  const unit = msaAreaWidth / numColumns / colWidth
14
16
  const left = -scrollX
@@ -48,11 +50,17 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
48
50
  const barHeight = 12
49
51
  const polygonHeight = minimapHeight - barHeight
50
52
  return (
51
- <div style={{ position: 'relative', height: minimapHeight, width: '100%' }}>
53
+ <div
54
+ style={{
55
+ position: 'relative',
56
+ height: minimapHeight,
57
+ width: '100%',
58
+ }}
59
+ >
52
60
  <div
53
61
  style={{
54
- boxSizing: 'border-box',
55
62
  height: barHeight,
63
+ boxSizing: 'border-box',
56
64
  border: '1px solid #555',
57
65
  }}
58
66
  />
@@ -67,8 +75,12 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
67
75
  width: w,
68
76
  zIndex: 100,
69
77
  }}
70
- onMouseOver={() => setHovered(true)}
71
- onMouseOut={() => setHovered(false)}
78
+ onMouseOver={() => {
79
+ setHovered(true)
80
+ }}
81
+ onMouseOut={() => {
82
+ setHovered(false)
83
+ }}
72
84
  onMouseDown={event => {
73
85
  setMouseDown({
74
86
  clientX: event.clientX,
@@ -75,7 +75,7 @@ const MSACanvasBlock = observer(function ({
75
75
  const { left, top } = ref.current.getBoundingClientRect()
76
76
  const mouseX = event.clientX - left + offsetX
77
77
  const mouseY = event.clientY - top + offsetY
78
- const x = Math.floor(mouseX / colWidth) + 1
78
+ const x = Math.floor(mouseX / colWidth)
79
79
  const y = Math.floor(mouseY / rowHeight)
80
80
  model.setMousePos(x, y)
81
81
  }}
@@ -86,7 +86,7 @@ const MSACanvasBlock = observer(function ({
86
86
  const { left, top } = ref.current.getBoundingClientRect()
87
87
  const mouseX = event.clientX - left + offsetX
88
88
  const mouseY = event.clientY - top + offsetY
89
- const x = Math.floor(mouseX / colWidth) + 1
89
+ const x = Math.floor(mouseX / colWidth)
90
90
  const y = Math.floor(mouseY / rowHeight)
91
91
  if (x === mouseClickCol && y === mouseClickRow) {
92
92
  model.setMouseClickPos(undefined, undefined)
@@ -94,7 +94,9 @@ const MSACanvasBlock = observer(function ({
94
94
  model.setMouseClickPos(x, y)
95
95
  }
96
96
  }}
97
- onMouseLeave={() => model.setMousePos()}
97
+ onMouseLeave={() => {
98
+ model.setMousePos()
99
+ }}
98
100
  width={blockSize * highResScaleFactor}
99
101
  height={blockSize * highResScaleFactor}
100
102
  style={{
@@ -6,7 +6,11 @@ import { autorun } from 'mobx'
6
6
  import type { MsaViewModel } from '../../model'
7
7
  import { renderMouseover } from './renderMSAMouseover'
8
8
 
9
- const MSAMouseoverCanvas = observer(({ model }: { model: MsaViewModel }) => {
9
+ const MSAMouseoverCanvas = observer(function ({
10
+ model,
11
+ }: {
12
+ model: MsaViewModel
13
+ }) {
10
14
  const ref = useRef<HTMLCanvasElement>(null)
11
15
  const { height, width } = model
12
16
  useEffect(() => {
@@ -55,7 +55,7 @@ function drawTiles({
55
55
  rowHeight,
56
56
  fillPalette,
57
57
  strokePalette,
58
- tidyFilteredGatheredAnnotations,
58
+ tidyFilteredGatheredInterProAnnotations,
59
59
  } = model
60
60
 
61
61
  for (const node of visibleLeaves) {
@@ -65,7 +65,7 @@ function drawTiles({
65
65
  } = node
66
66
  const y = x!
67
67
 
68
- const entry = tidyFilteredGatheredAnnotations?.[name]
68
+ const entry = tidyFilteredGatheredInterProAnnotations[name]
69
69
 
70
70
  let j = 0
71
71
  if (entry) {
@@ -73,8 +73,8 @@ function drawTiles({
73
73
  const m1 = model.seqCoordToRowSpecificGlobalCoord(name, start - 1)
74
74
  const m2 = model.seqCoordToRowSpecificGlobalCoord(name, end)
75
75
  const x = m1 * colWidth
76
- ctx.fillStyle = fillPalette[accession]
77
- ctx.strokeStyle = strokePalette[accession]
76
+ ctx.fillStyle = fillPalette[accession]!
77
+ ctx.strokeStyle = strokePalette[accession]!
78
78
  const h = subFeatureRows ? 4 : rowHeight
79
79
  const t = y - rowHeight + (subFeatureRows ? j * h : 0)
80
80
  const lw = colWidth * (m2 - m1)
@@ -110,22 +110,22 @@ function drawTiles({
110
110
  data: { name },
111
111
  } = node
112
112
  const y = node.x!
113
- const str = columns[name]?.slice(xStart, xEnd)
114
- for (let i = 0; i < str?.length; i++) {
115
- const letter = str[i]
113
+ const str = columns[name]!.slice(xStart, xEnd)
114
+ for (let i = 0; i < str.length; i++) {
115
+ const letter = str[i]!
116
116
  const color =
117
117
  colorSchemeName === 'clustalx_protein_dynamic'
118
118
  ? getClustalXColor(
119
- colStats[xStart + i],
120
- colStatsSums[xStart + i],
119
+ colStats[xStart + i]!,
120
+ colStatsSums[xStart + i]!,
121
121
  model,
122
122
  name,
123
123
  xStart + i,
124
124
  )
125
125
  : colorSchemeName === 'percent_identity_dynamic'
126
126
  ? getPercentIdentityColor(
127
- colStats[xStart + i],
128
- colStatsSums[xStart + i],
127
+ colStats[xStart + i]!,
128
+ colStatsSums[xStart + i]!,
129
129
  model,
130
130
  name,
131
131
  xStart + i,
@@ -178,9 +178,9 @@ function drawText({
178
178
  data: { name },
179
179
  } = node
180
180
  const y = node.x!
181
- const str = columns[name]?.slice(xStart, xEnd)
182
- for (let i = 0; i < str?.length; i++) {
183
- const letter = str[i]
181
+ const str = columns[name]!.slice(xStart, xEnd)
182
+ for (let i = 0; i < str.length; i++) {
183
+ const letter = str[i]!
184
184
  const color = colorScheme[letter.toUpperCase()]
185
185
  const contrast = contrastLettering
186
186
  ? contrastScheme[letter.toUpperCase()] || 'black'
@@ -28,7 +28,7 @@ export function renderMouseover({
28
28
  ctx.clearRect(0, 0, width, height)
29
29
  if (mouseCol !== undefined) {
30
30
  ctx.fillStyle = hoverColor
31
- ctx.fillRect((mouseCol - 1) * colWidth + scrollX, 0, colWidth, height)
31
+ ctx.fillRect(mouseCol * colWidth + scrollX, 0, colWidth, height)
32
32
  }
33
33
  if (mouseRow !== undefined) {
34
34
  ctx.fillStyle = hoverColor
@@ -36,7 +36,7 @@ export function renderMouseover({
36
36
  }
37
37
  if (mouseClickCol !== undefined) {
38
38
  ctx.fillStyle = highlightColor
39
- ctx.fillRect((mouseClickCol - 1) * colWidth + scrollX, 0, colWidth, height)
39
+ ctx.fillRect(mouseClickCol * colWidth + scrollX, 0, colWidth, height)
40
40
  }
41
41
  if (mouseClickRow !== undefined) {
42
42
  ctx.fillStyle = highlightColor
@@ -44,6 +44,6 @@ export function renderMouseover({
44
44
  }
45
45
  if (mouseCol2 !== undefined) {
46
46
  ctx.fillStyle = highlightColor
47
- ctx.fillRect((mouseCol2 - 1) * colWidth + scrollX, 0, colWidth, height)
47
+ ctx.fillRect(mouseCol2 * colWidth + scrollX, 0, colWidth, height)
48
48
  }
49
49
  }
@@ -50,9 +50,11 @@ const TreeBranchMenu = observer(function ({
50
50
  <MenuItem
51
51
  dense
52
52
  onClick={() => {
53
- model.showOnly === node.id
54
- ? model.setShowOnly(undefined)
55
- : model.setShowOnly(node.id)
53
+ if (model.showOnly === node.id) {
54
+ model.setShowOnly(undefined)
55
+ } else {
56
+ model.setShowOnly(node.id)
57
+ }
56
58
  onClose()
57
59
  }}
58
60
  >
@@ -50,6 +50,7 @@ const TreeCanvasBlock = observer(function ({
50
50
  const w2 = width * highResScaleFactor
51
51
  const h2 = height * highResScaleFactor
52
52
 
53
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
53
54
  const vref = useCallback(
54
55
  (arg: HTMLCanvasElement) => {
55
56
  model.incrementRef()
@@ -136,7 +137,9 @@ const TreeCanvasBlock = observer(function ({
136
137
  <TreeBranchMenu
137
138
  node={branchMenu}
138
139
  model={model}
139
- onClose={() => setBranchMenu(undefined)}
140
+ onClose={() => {
141
+ setBranchMenu(undefined)
142
+ }}
140
143
  />
141
144
  ) : null}
142
145
 
@@ -144,7 +147,9 @@ const TreeCanvasBlock = observer(function ({
144
147
  <TreeNodeMenu
145
148
  node={toggleNodeMenu}
146
149
  model={model}
147
- onClose={() => setToggleNodeMenu(undefined)}
150
+ onClose={() => {
151
+ setToggleNodeMenu(undefined)
152
+ }}
148
153
  />
149
154
  ) : null}
150
155
 
@@ -166,7 +171,7 @@ const TreeCanvasBlock = observer(function ({
166
171
 
167
172
  const data = hoverBranchClickMap(event)
168
173
  if (data?.id) {
169
- setBranchMenu({ ...data, x, y })
174
+ setBranchMenu({ x, y, id: data.id, name: data.name })
170
175
  }
171
176
 
172
177
  const data2 = hoverNameClickMap(event)
@@ -174,7 +179,9 @@ const TreeCanvasBlock = observer(function ({
174
179
  setToggleNodeMenu({ ...data2, x, y })
175
180
  }
176
181
  }}
177
- onMouseLeave={() => setHoverElt(undefined)}
182
+ onMouseLeave={() => {
183
+ setHoverElt(undefined)
184
+ }}
178
185
  ref={vref}
179
186
  />
180
187
  <canvas
@@ -58,7 +58,7 @@ const TreeMenu = observer(function ({
58
58
  model.toggleCollapsed(node.id)
59
59
  } else {
60
60
  if (node.id.endsWith('-leafnode')) {
61
- model.toggleCollapsed2(`${node.id}`)
61
+ model.toggleCollapsed2(node.id)
62
62
  } else {
63
63
  model.toggleCollapsed2(`${node.id}-leafnode`)
64
64
  }
@@ -11,7 +11,7 @@ import {
11
11
  import type { MsaViewModel } from '../../../model'
12
12
  import SequenceTextArea from '../../SequenceTextArea'
13
13
 
14
- export default observer(function ({
14
+ const TreeNodeInfoDialog = observer(function ({
15
15
  info,
16
16
  model,
17
17
  nodeName,
@@ -26,7 +26,14 @@ export default observer(function ({
26
26
  const metadata = treeMetadata[nodeName]
27
27
  const [name, sequence] = rows.find(f => f[0] === nodeName)!
28
28
  return (
29
- <Dialog onClose={() => onClose()} open title="Tree node info" maxWidth="xl">
29
+ <Dialog
30
+ onClose={() => {
31
+ onClose()
32
+ }}
33
+ open
34
+ title="Tree node info"
35
+ maxWidth="xl"
36
+ >
30
37
  <DialogContent>
31
38
  <BaseCard title="Attributes">
32
39
  <Attributes attributes={{ nodeName, ...info }} />
@@ -43,3 +50,5 @@ export default observer(function ({
43
50
  </Dialog>
44
51
  )
45
52
  })
53
+
54
+ export default TreeNodeInfoDialog
@@ -11,7 +11,7 @@ export function chooseGridPitch(
11
11
  scale = Math.abs(scale)
12
12
  const minMajorPitchBp = minMajorPitchPx * scale
13
13
  const majorMagnitude = Number.parseInt(
14
- Number(minMajorPitchBp).toExponential().split(/e/i)[1],
14
+ Number(minMajorPitchBp).toExponential().split(/e/i)[1]!,
15
15
  10,
16
16
  )
17
17
 
@@ -50,9 +50,6 @@ export function makeTicks(
50
50
 
51
51
  let minBase = start
52
52
  let maxBase = end
53
- if (minBase === null || maxBase === null) {
54
- return []
55
- }
56
53
 
57
54
  if (bpPerPx < 0) {
58
55
  ;[minBase, maxBase] = [maxBase, minBase]
@@ -19,7 +19,7 @@ const palettes = [
19
19
  ]
20
20
 
21
21
  export function getPalette(l: number) {
22
- return palettes[Math.min(l, palettes.length - 1)]
22
+ return palettes[Math.min(l, palettes.length - 1)]!
23
23
  }
24
24
 
25
25
  export default palettes
@@ -38,7 +38,7 @@ async function runInterProScan({
38
38
  method: 'POST',
39
39
  body: new URLSearchParams({
40
40
  email: 'colin.diesh@gmail.com',
41
- sequence: `${seq}`,
41
+ sequence: seq,
42
42
  programs: programs.join(','),
43
43
  }),
44
44
  })
@@ -47,7 +47,7 @@ async function runInterProScan({
47
47
  jobId,
48
48
  onProgress,
49
49
  })
50
- return loadInterProScanResultsWithStatus({ jobId, model })
50
+ await loadInterProScanResultsWithStatus({ jobId, model })
51
51
  }
52
52
 
53
53
  export function loadInterProScanResults(jobId: string) {
@@ -65,6 +65,7 @@ async function wait({
65
65
  }) {
66
66
  const url = `${base}/iprscan5/status/${jobId}`
67
67
  try {
68
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
68
69
  while (true) {
69
70
  for (let i = 0; i < 10; i++) {
70
71
  await timeout(1000)
@@ -101,14 +102,13 @@ export async function launchInterProScan({
101
102
  try {
102
103
  onProgress({ msg: `Launching ${algorithm} MSA` })
103
104
  if (algorithm === 'interproscan') {
104
- const result = await runInterProScan({
105
+ await runInterProScan({
105
106
  seq,
106
107
  onJobId,
107
108
  onProgress,
108
109
  programs,
109
110
  model,
110
111
  })
111
- return result
112
112
  }
113
113
  throw new Error('unknown algorithm')
114
114
  } finally {
@@ -130,7 +130,7 @@ export async function loadInterProScanResultsWithStatus({
130
130
  })
131
131
  const ret = await loadInterProScanResults(jobId)
132
132
  model.setInterProAnnotations(
133
- Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
133
+ Object.fromEntries(ret.results.map(r => [r.xref[0]!.id, r])),
134
134
  )
135
135
  model.setShowDomains(true)
136
136
  getSession(model).notify(`Loaded interproscan ${jobId} results`, 'success')
@@ -8,7 +8,6 @@ export function DialogQueueSessionMixin() {
8
8
  return types
9
9
  .model('DialogQueueSessionMixin', {})
10
10
  .volatile(() => ({
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
11
  queueOfDialogs: [] as [DialogComponentType, any][],
13
12
  }))
14
13
  .views(self => ({