react-msaview 5.10.0 → 6.1.0

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 (226) hide show
  1. package/bundle/index.js +99 -99
  2. package/bundle/index.js.map +4 -4
  3. package/dist/clustalX.js +22 -22
  4. package/dist/clustalX.js.map +1 -1
  5. package/dist/columnCounts.d.ts +7 -0
  6. package/dist/columnCounts.js +18 -0
  7. package/dist/columnCounts.js.map +1 -1
  8. package/dist/components/CopyButton.d.ts +9 -0
  9. package/dist/components/CopyButton.js +23 -0
  10. package/dist/components/CopyButton.js.map +1 -0
  11. package/dist/components/DragHandle.d.ts +25 -0
  12. package/dist/components/DragHandle.js +49 -0
  13. package/dist/components/DragHandle.js.map +1 -0
  14. package/dist/components/Loading.js +2 -2
  15. package/dist/components/Loading.js.map +1 -1
  16. package/dist/components/MSAView.js +2 -2
  17. package/dist/components/MSAView.js.map +1 -1
  18. package/dist/components/ResizeHandles.d.ts +4 -2
  19. package/dist/components/ResizeHandles.js +35 -54
  20. package/dist/components/ResizeHandles.js.map +1 -1
  21. package/dist/components/SequenceTextArea.js +3 -10
  22. package/dist/components/SequenceTextArea.js.map +1 -1
  23. package/dist/components/VerticalScrollbar.js +11 -25
  24. package/dist/components/VerticalScrollbar.js.map +1 -1
  25. package/dist/components/dialogs/FeatureDialog.js +3 -3
  26. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  27. package/dist/components/dialogs/InterProScanDialog.js +52 -129
  28. package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
  29. package/dist/components/dialogs/{UserProvidedDomainsDialog.d.ts → InterProScanFileDialog.d.ts} +2 -2
  30. package/dist/components/dialogs/{UserProvidedDomainsDialog.js → InterProScanFileDialog.js} +6 -10
  31. package/dist/components/dialogs/InterProScanFileDialog.js.map +1 -0
  32. package/dist/components/dialogs/TrackInfoDialog.d.ts +2 -4
  33. package/dist/components/dialogs/TrackInfoDialog.js +8 -14
  34. package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
  35. package/dist/components/header/FileMenu.js +3 -3
  36. package/dist/components/header/FileMenu.js.map +1 -1
  37. package/dist/components/header/GappynessSlider.js +1 -1
  38. package/dist/components/header/GappynessSlider.js.map +1 -1
  39. package/dist/components/header/{getDomainsMenu.d.ts → getAnnotationsMenu.d.ts} +1 -1
  40. package/dist/components/header/{getDomainsMenu.js → getAnnotationsMenu.js} +10 -9
  41. package/dist/components/header/getAnnotationsMenu.js.map +1 -0
  42. package/dist/components/header/settingsMenuItems.js +15 -0
  43. package/dist/components/header/settingsMenuItems.js.map +1 -1
  44. package/dist/components/import/ImportForm.js +1 -1
  45. package/dist/components/import/ImportForm.js.map +1 -1
  46. package/dist/components/import/ImportFormExamples.js +66 -57
  47. package/dist/components/import/ImportFormExamples.js.map +1 -1
  48. package/dist/components/minimap/Minimap.js +40 -23
  49. package/dist/components/minimap/Minimap.js.map +1 -1
  50. package/dist/components/minimap/MinimapSVG.d.ts +2 -1
  51. package/dist/components/minimap/MinimapSVG.js +3 -4
  52. package/dist/components/minimap/MinimapSVG.js.map +1 -1
  53. package/dist/components/minimap/minimapLayout.d.ts +10 -1
  54. package/dist/components/minimap/minimapLayout.js +15 -10
  55. package/dist/components/minimap/minimapLayout.js.map +1 -1
  56. package/dist/components/msa/{DomainLegend.d.ts → AnnotationLegend.d.ts} +2 -2
  57. package/dist/components/msa/{DomainLegend.js → AnnotationLegend.js} +4 -4
  58. package/dist/components/msa/AnnotationLegend.js.map +1 -0
  59. package/dist/components/msa/MSACanvas.js +9 -3
  60. package/dist/components/msa/MSACanvas.js.map +1 -1
  61. package/dist/components/msa/MSACanvasBlock.js +12 -3
  62. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  63. package/dist/components/msa/MSAMouseoverCanvas.js +1 -2
  64. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  65. package/dist/components/msa/MSAPanel.js +2 -2
  66. package/dist/components/msa/MSAPanel.js.map +1 -1
  67. package/dist/components/msa/domainBandCursor.d.ts +17 -0
  68. package/dist/components/msa/domainBandCursor.js +39 -0
  69. package/dist/components/msa/domainBandCursor.js.map +1 -0
  70. package/dist/components/msa/msaRaster.d.ts +63 -0
  71. package/dist/components/msa/msaRaster.js +252 -0
  72. package/dist/components/msa/msaRaster.js.map +1 -0
  73. package/dist/components/msa/renderMSABlock.d.ts +2 -1
  74. package/dist/components/msa/renderMSABlock.js +27 -41
  75. package/dist/components/msa/renderMSABlock.js.map +1 -1
  76. package/dist/components/msa/renderMSAMouseover.js +1 -2
  77. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  78. package/dist/components/msa/tileColor.d.ts +6 -0
  79. package/dist/components/msa/tileColor.js +35 -0
  80. package/dist/components/msa/tileColor.js.map +1 -0
  81. package/dist/components/renderCtx.d.ts +1 -1
  82. package/dist/components/tracks/TrackBlocks.d.ts +14 -0
  83. package/dist/components/tracks/TrackBlocks.js +65 -0
  84. package/dist/components/tracks/TrackBlocks.js.map +1 -0
  85. package/dist/components/tracks/{renderTracksSvg.d.ts → drawTracks.d.ts} +22 -10
  86. package/dist/components/tracks/drawTracks.js +193 -0
  87. package/dist/components/tracks/drawTracks.js.map +1 -0
  88. package/dist/components/tree/TreeCanvas.js +8 -2
  89. package/dist/components/tree/TreeCanvas.js.map +1 -1
  90. package/dist/components/tree/TreeCanvasBlock.js +7 -4
  91. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  92. package/dist/components/tree/TreeRuler.js +5 -2
  93. package/dist/components/tree/TreeRuler.js.map +1 -1
  94. package/dist/components/tree/renderTreeCanvas.js +5 -2
  95. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  96. package/dist/constants.d.ts +3 -0
  97. package/dist/constants.js +8 -0
  98. package/dist/constants.js.map +1 -1
  99. package/dist/ggplotPalettes.d.ts +0 -1
  100. package/dist/ggplotPalettes.js +0 -3
  101. package/dist/ggplotPalettes.js.map +1 -1
  102. package/dist/hierarchy.d.ts +2 -6
  103. package/dist/hierarchy.js +4 -6
  104. package/dist/hierarchy.js.map +1 -1
  105. package/dist/index.d.ts +2 -2
  106. package/dist/launchInterProScan.d.ts +0 -23
  107. package/dist/launchInterProScan.js +2 -5
  108. package/dist/launchInterProScan.js.map +1 -1
  109. package/dist/measureTextCanvas.js +21 -6
  110. package/dist/measureTextCanvas.js.map +1 -1
  111. package/dist/model/DataModel.d.ts +1 -4
  112. package/dist/model/DataModel.js +8 -10
  113. package/dist/model/DataModel.js.map +1 -1
  114. package/dist/model.d.ts +86 -107
  115. package/dist/model.js +238 -162
  116. package/dist/model.js.map +1 -1
  117. package/dist/neighborJoining.js +34 -18
  118. package/dist/neighborJoining.js.map +1 -1
  119. package/dist/renderTestEnv.d.ts +43 -0
  120. package/dist/renderTestEnv.js +88 -0
  121. package/dist/renderTestEnv.js.map +1 -0
  122. package/dist/renderToSvg.js +3 -3
  123. package/dist/renderToSvg.js.map +1 -1
  124. package/dist/rowCoordinateCalculations.d.ts +13 -17
  125. package/dist/rowCoordinateCalculations.js +45 -39
  126. package/dist/rowCoordinateCalculations.js.map +1 -1
  127. package/dist/sequenceLogo.d.ts +28 -0
  128. package/dist/sequenceLogo.js +47 -0
  129. package/dist/sequenceLogo.js.map +1 -0
  130. package/dist/types.d.ts +6 -11
  131. package/dist/version.d.ts +1 -1
  132. package/dist/version.js +1 -1
  133. package/dist/version.js.map +1 -1
  134. package/package.json +5 -5
  135. package/src/clustalX.ts +22 -22
  136. package/src/colSpace.test.ts +27 -0
  137. package/src/columnCounts.test.ts +15 -0
  138. package/src/columnCounts.ts +19 -0
  139. package/src/components/CopyButton.tsx +44 -0
  140. package/src/components/DragHandle.tsx +81 -0
  141. package/src/components/Loading.tsx +10 -1
  142. package/src/components/MSAView.tsx +2 -3
  143. package/src/components/ResizeHandles.tsx +70 -87
  144. package/src/components/SequenceTextArea.tsx +3 -16
  145. package/src/components/VerticalScrollbar.tsx +20 -33
  146. package/src/components/dialogs/FeatureDialog.tsx +3 -4
  147. package/src/components/dialogs/InterProScanDialog.tsx +54 -131
  148. package/src/components/dialogs/{UserProvidedDomainsDialog.tsx → InterProScanFileDialog.tsx} +6 -14
  149. package/src/components/dialogs/TrackInfoDialog.tsx +18 -20
  150. package/src/components/header/FileMenu.tsx +3 -3
  151. package/src/components/header/GappynessSlider.tsx +4 -1
  152. package/src/components/header/{getDomainsMenu.ts → getAnnotationsMenu.ts} +10 -9
  153. package/src/components/header/settingsMenuItems.ts +18 -0
  154. package/src/components/import/ImportForm.tsx +1 -1
  155. package/src/components/import/ImportFormExamples.tsx +82 -133
  156. package/src/components/minimap/Minimap.tsx +67 -32
  157. package/src/components/minimap/MinimapSVG.tsx +32 -31
  158. package/src/components/minimap/minimapLayout.test.ts +60 -0
  159. package/src/components/minimap/minimapLayout.ts +15 -10
  160. package/src/components/msa/{DomainLegend.tsx → AnnotationLegend.tsx} +7 -3
  161. package/src/components/msa/MSACanvas.tsx +24 -11
  162. package/src/components/msa/MSACanvasBlock.tsx +13 -3
  163. package/src/components/msa/MSAMouseoverCanvas.tsx +1 -3
  164. package/src/components/msa/MSAPanel.tsx +2 -2
  165. package/src/components/msa/domainBandCursor.ts +41 -0
  166. package/src/components/msa/msaRaster.test.ts +145 -0
  167. package/src/components/msa/msaRaster.ts +350 -0
  168. package/src/components/msa/renderMSABlock.ts +34 -43
  169. package/src/components/msa/renderMSAMouseover.ts +1 -3
  170. package/src/components/msa/tileColor.ts +37 -0
  171. package/src/components/renderCtx.ts +2 -0
  172. package/src/components/tracks/TrackBlocks.tsx +111 -0
  173. package/src/components/tracks/drawTracks.ts +323 -0
  174. package/src/components/tree/TreeCanvas.tsx +16 -4
  175. package/src/components/tree/TreeCanvasBlock.tsx +18 -11
  176. package/src/components/tree/TreeRuler.tsx +7 -2
  177. package/src/components/tree/renderTreeCanvas.test.ts +15 -7
  178. package/src/components/tree/renderTreeCanvas.ts +5 -1
  179. package/src/constants.ts +10 -0
  180. package/src/domainBands.test.ts +24 -0
  181. package/src/domainLetterColor.test.ts +80 -0
  182. package/src/ggplotPalettes.ts +0 -4
  183. package/src/hierarchy.test.ts +7 -7
  184. package/src/hierarchy.ts +6 -9
  185. package/src/impgRender.test.tsx +2 -57
  186. package/src/index.ts +4 -1
  187. package/src/largeTree.test.ts +39 -4
  188. package/src/launchInterProScan.ts +3 -30
  189. package/src/loadErrorDisplay.test.tsx +102 -0
  190. package/src/measureTextCanvas.ts +22 -6
  191. package/src/model/DataModel.ts +11 -11
  192. package/src/model.ts +262 -172
  193. package/src/neighborJoining.ts +36 -18
  194. package/src/renderDomainsSvg.test.tsx +2 -57
  195. package/src/renderMinimapSvg.test.tsx +55 -0
  196. package/src/renderSequenceLogoSvg.test.tsx +176 -0
  197. package/src/renderTestEnv.ts +96 -0
  198. package/src/renderToSvg.tsx +3 -3
  199. package/src/rowCoordinateCalculations.ts +48 -44
  200. package/src/sequenceLogo.test.ts +88 -0
  201. package/src/sequenceLogo.ts +63 -0
  202. package/src/types.ts +17 -16
  203. package/src/version.ts +1 -1
  204. package/src/viewChrome.test.tsx +134 -0
  205. package/dist/components/ConservationTrack.d.ts +0 -8
  206. package/dist/components/ConservationTrack.js +0 -49
  207. package/dist/components/ConservationTrack.js.map +0 -1
  208. package/dist/components/TextTrack.d.ts +0 -8
  209. package/dist/components/TextTrack.js +0 -58
  210. package/dist/components/TextTrack.js.map +0 -1
  211. package/dist/components/dialogs/DomainDialog.d.ts +0 -6
  212. package/dist/components/dialogs/DomainDialog.js +0 -19
  213. package/dist/components/dialogs/DomainDialog.js.map +0 -1
  214. package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +0 -1
  215. package/dist/components/header/SettingsMenu.d.ts +0 -6
  216. package/dist/components/header/SettingsMenu.js +0 -40
  217. package/dist/components/header/SettingsMenu.js.map +0 -1
  218. package/dist/components/header/getDomainsMenu.js.map +0 -1
  219. package/dist/components/msa/DomainLegend.js.map +0 -1
  220. package/dist/components/tracks/renderTracksSvg.js +0 -126
  221. package/dist/components/tracks/renderTracksSvg.js.map +0 -1
  222. package/src/components/ConservationTrack.tsx +0 -99
  223. package/src/components/TextTrack.tsx +0 -103
  224. package/src/components/dialogs/DomainDialog.tsx +0 -45
  225. package/src/components/header/SettingsMenu.tsx +0 -57
  226. package/src/components/tracks/renderTracksSvg.ts +0 -247
@@ -1,48 +1,30 @@
1
- import React, { useCallback, useState } from 'react'
1
+ import React, { useCallback } from 'react'
2
2
 
3
3
  import { observer } from 'mobx-react'
4
4
 
5
- import { useDragScroll } from '../useDragScroll.ts'
5
+ import DragHandle from './DragHandle.tsx'
6
6
 
7
7
  import type { MsaViewModel } from '../model.ts'
8
-
9
- const handleBg = 'rgba(200,200,200)'
10
- const handleBgHover = 'rgba(150,150,150)'
8
+ import type { TrackKind } from '../types.ts'
11
9
 
12
10
  export const VerticalResizeHandle = observer(function ({
13
11
  model,
14
12
  }: {
15
13
  model: MsaViewModel
16
14
  }) {
17
- const { resizeHandleWidth } = model
18
- const [hovered, setHovered] = useState(false)
19
- const { startDrag } = useDragScroll(
20
- 'x',
21
- useCallback(
22
- (delta: number, startWidth: number) => {
23
- model.setTreeAreaWidth(startWidth + delta)
24
- },
25
- [model],
26
- ),
15
+ const onDrag = useCallback(
16
+ (delta: number, startWidth: number) => {
17
+ model.setTreeAreaWidth(startWidth + delta)
18
+ },
19
+ [model],
27
20
  )
28
-
29
21
  return (
30
- <div
31
- onMouseDown={event => {
32
- startDrag(event, model.treeAreaWidth)
33
- }}
34
- onMouseEnter={() => {
35
- setHovered(true)
36
- }}
37
- onMouseLeave={() => {
38
- setHovered(false)
39
- }}
40
- style={{
41
- cursor: 'ew-resize',
42
- width: resizeHandleWidth,
43
- background: hovered ? handleBgHover : handleBg,
44
- position: 'relative',
45
- }}
22
+ <DragHandle
23
+ axis="x"
24
+ variant="resizer"
25
+ getStart={() => model.treeAreaWidth}
26
+ onDrag={onDrag}
27
+ style={{ width: model.resizeHandleWidth }}
46
28
  />
47
29
  )
48
30
  })
@@ -52,78 +34,79 @@ export const HorizontalResizeHandle = observer(function ({
52
34
  }: {
53
35
  model: MsaViewModel
54
36
  }) {
55
- const { resizeHandleWidth } = model
56
- const [hovered, setHovered] = useState(false)
57
- const { startDrag } = useDragScroll(
58
- 'y',
59
- useCallback(
60
- (delta: number, startHeight: number) => {
61
- model.setHeight(startHeight + delta)
62
- },
63
- [model],
64
- ),
37
+ const onDrag = useCallback(
38
+ (delta: number, startHeight: number) => {
39
+ model.setHeight(startHeight + delta)
40
+ },
41
+ [model],
65
42
  )
66
-
67
43
  return (
68
- <div
69
- onMouseDown={event => {
70
- startDrag(event, model.height)
71
- }}
72
- onMouseEnter={() => {
73
- setHovered(true)
74
- }}
75
- onMouseLeave={() => {
76
- setHovered(false)
77
- }}
78
- style={{
79
- cursor: 'ns-resize',
80
- width: '100%',
81
- height: resizeHandleWidth,
82
- background: hovered ? handleBgHover : handleBg,
83
- position: 'relative',
84
- }}
44
+ <DragHandle
45
+ axis="y"
46
+ variant="resizer"
47
+ getStart={() => model.height}
48
+ onDrag={onDrag}
49
+ style={{ width: '100%', height: model.resizeHandleWidth }}
85
50
  />
86
51
  )
87
52
  })
88
53
 
89
- export const ConservationTrackResizeHandle = observer(function ({
54
+ // The height behind each resizable track kind. Both bar tracks read one height
55
+ // so conservation and property conservation stay directly comparable; the logo
56
+ // keeps its own, being taller by default. Text tracks are absent: they are one
57
+ // alignment row tall and follow rowHeight, so the zoom controls already size
58
+ // them.
59
+ const trackHeights: Partial<
60
+ Record<
61
+ TrackKind,
62
+ {
63
+ get: (model: MsaViewModel) => number
64
+ set: (model: MsaViewModel, height: number) => void
65
+ }
66
+ >
67
+ > = {
68
+ bar: {
69
+ get: model => model.conservationTrackHeight,
70
+ set: (model, height) => {
71
+ model.setConservationTrackHeight(height)
72
+ },
73
+ },
74
+ logo: {
75
+ get: model => model.sequenceLogoTrackHeight,
76
+ set: (model, height) => {
77
+ model.setSequenceLogoTrackHeight(height)
78
+ },
79
+ },
80
+ }
81
+
82
+ export const TrackResizeHandle = observer(function ({
90
83
  model,
84
+ kind,
91
85
  }: {
92
86
  model: MsaViewModel
87
+ kind: TrackKind
93
88
  }) {
94
- const { resizeHandleWidth } = model
95
- const [hovered, setHovered] = useState(false)
96
- const { startDrag } = useDragScroll(
97
- 'y',
98
- useCallback(
99
- (delta: number, startHeight: number) => {
100
- model.setConservationTrackHeight(Math.max(10, startHeight + delta))
101
- },
102
- [model],
103
- ),
89
+ const height = trackHeights[kind]
90
+ const onDrag = useCallback(
91
+ (delta: number, startHeight: number) => {
92
+ height?.set(model, Math.max(10, startHeight + delta))
93
+ },
94
+ [model, height],
104
95
  )
105
-
106
- return (
107
- <div
108
- onMouseDown={event => {
109
- startDrag(event, model.conservationTrackHeight)
110
- }}
111
- onMouseEnter={() => {
112
- setHovered(true)
113
- }}
114
- onMouseLeave={() => {
115
- setHovered(false)
116
- }}
96
+ return height ? (
97
+ <DragHandle
98
+ axis="y"
99
+ variant="resizer"
100
+ getStart={() => height.get(model)}
101
+ onDrag={onDrag}
117
102
  style={{
118
103
  position: 'absolute',
119
104
  bottom: 0,
120
105
  left: 0,
121
- cursor: 'ns-resize',
122
106
  width: '100%',
123
- height: resizeHandleWidth,
107
+ height: model.resizeHandleWidth,
124
108
  zIndex: 1,
125
- background: hovered ? handleBgHover : handleBg,
126
109
  }}
127
110
  />
128
- )
111
+ ) : null
129
112
  })
@@ -1,11 +1,11 @@
1
1
  import React, { useState } from 'react'
2
2
 
3
3
  import { makeStyles } from '@jbrowse/core/util/tss-react'
4
- import { Button, TextField } from '@mui/material'
4
+ import { TextField } from '@mui/material'
5
5
  import { getUngappedSequence } from 'msa-parsers'
6
6
 
7
- import copy from '../vendor/copyToClipboard.ts'
8
7
  import Checkbox2 from './Checkbox2.tsx'
8
+ import CopyButton from './CopyButton.tsx'
9
9
 
10
10
  const useStyles = makeStyles()({
11
11
  textAreaFont: {
@@ -21,7 +21,6 @@ const useStyles = makeStyles()({
21
21
 
22
22
  export default function SequenceTextArea({ str }: { str: [string, string][] }) {
23
23
  const { classes } = useStyles()
24
- const [copied, setCopied] = useState(false)
25
24
  const [showGaps, setShowGaps] = useState(false)
26
25
  const [showEmpty, setShowEmpty] = useState(false)
27
26
 
@@ -32,19 +31,7 @@ export default function SequenceTextArea({ str }: { str: [string, string][] }) {
32
31
  .join('\n')
33
32
  return (
34
33
  <>
35
- <Button
36
- color="primary"
37
- variant="contained"
38
- onClick={() => {
39
- copy(disp)
40
- setCopied(true)
41
- setTimeout(() => {
42
- setCopied(false)
43
- }, 500)
44
- }}
45
- >
46
- {copied ? 'Copied!' : 'Copy to clipboard'}
47
- </Button>
34
+ <CopyButton text={disp} />
48
35
  <Checkbox2
49
36
  label="Show gaps"
50
37
  checked={showGaps}
@@ -1,61 +1,48 @@
1
- import React, { useCallback, useState } from 'react'
1
+ import React, { useCallback } from 'react'
2
2
 
3
- import { clamp } from '@jbrowse/core/util'
4
3
  import { observer } from 'mobx-react'
5
4
 
6
- import { useDragScroll } from '../useDragScroll.ts'
5
+ import DragHandle from './DragHandle.tsx'
7
6
 
8
7
  import type { MsaViewModel } from '../model.ts'
9
8
 
9
+ const width = 20
10
+
10
11
  const VerticalScrollbar = observer(({ model }: { model: MsaViewModel }) => {
11
12
  const { msaAreaHeight, scrollY, totalHeight } = model
12
- const [hovered, setHovered] = useState(false)
13
- const fill = 'rgba(66, 119, 127, 0.3)'
14
13
  const unit = msaAreaHeight / totalHeight
15
- const top = -scrollY
16
- const bottom = top + msaAreaHeight
17
- const t = top * unit
18
- const b = bottom * unit
19
- const { startDrag } = useDragScroll(
20
- 'y',
21
- useCallback(
22
- (delta: number, startScroll: number) => {
23
- model.setScrollY(clamp(startScroll - delta / unit, model.maxScrollY, 0))
24
- },
25
- [model, unit],
26
- ),
14
+ const t = -scrollY * unit
15
+ const b = (-scrollY + msaAreaHeight) * unit
16
+
17
+ const onDrag = useCallback(
18
+ (delta: number, startScroll: number) => {
19
+ model.setScrollY(startScroll - delta / unit)
20
+ },
21
+ [model, unit],
27
22
  )
23
+
28
24
  return (
29
25
  <div
30
26
  style={{
31
27
  position: 'relative',
32
- width: 20,
28
+ width,
33
29
  height: msaAreaHeight,
34
30
  borderLeft: '1px solid #555',
35
31
  borderTop: '1px solid #555',
36
32
  boxSizing: 'border-box',
37
33
  }}
38
34
  >
39
- <div
35
+ <DragHandle
36
+ axis="y"
37
+ variant="thumb"
38
+ getStart={() => model.scrollY}
39
+ onDrag={onDrag}
40
40
  style={{
41
- position: 'absolute',
42
41
  top: Math.max(0, t),
43
42
  left: 0,
44
- background: hovered ? 'rgba(66,119,127,0.6)' : fill,
45
- cursor: 'pointer',
46
43
  boxSizing: 'border-box',
47
- width: 20,
44
+ width,
48
45
  height: Math.max(b - t, 20),
49
- zIndex: 100,
50
- }}
51
- onMouseOver={() => {
52
- setHovered(true)
53
- }}
54
- onMouseOut={() => {
55
- setHovered(false)
56
- }}
57
- onMouseDown={event => {
58
- startDrag(event, model.scrollY)
59
46
  }}
60
47
  />
61
48
  </div>
@@ -43,10 +43,9 @@ const Toggles = observer(function ({ model }: { model: MsaViewModel }) {
43
43
  })
44
44
 
45
45
  const FeatureTable = observer(function ({ model }: { model: MsaViewModel }) {
46
- const { tidyInterProAnnotationTypes, tidyInterProAnnotations, fillPalette } =
47
- model
46
+ const { annotationTypes, annotations, fillPalette } = model
48
47
  const counts = new Map<string, number>()
49
- for (const annot of tidyInterProAnnotations) {
48
+ for (const annot of annotations) {
50
49
  counts.set(annot.accession, (counts.get(annot.accession) ?? 0) + 1)
51
50
  }
52
51
  return (
@@ -64,7 +63,7 @@ const FeatureTable = observer(function ({ model }: { model: MsaViewModel }) {
64
63
  </TableRow>
65
64
  </TableHead>
66
65
  <TableBody>
67
- {[...tidyInterProAnnotationTypes.values()].map(
66
+ {[...annotationTypes.values()].map(
68
67
  ({ accession, name, description }) => (
69
68
  <TableRow key={accession}>
70
69
  <TableCell padding="checkbox">
@@ -10,6 +10,57 @@ import { launchInterProScan } from '../../launchInterProScan.ts'
10
10
 
11
11
  import type { MsaViewModel } from '../../model.ts'
12
12
 
13
+ const FAMILIES = 'Families, domains, sites & repeats'
14
+ const FEATURES = 'Other sequence features'
15
+ const STRUCTURAL = 'Structural domains'
16
+ const OTHER = 'Other category'
17
+
18
+ // The analyses the EBI iprscan5 endpoint accepts, all on by default. Static, so
19
+ // it lives out here rather than being rebuilt on every render of the dialog.
20
+ const interProScanPrograms = [
21
+ {
22
+ name: 'NCBIfam',
23
+ category: FAMILIES,
24
+ description: 'NCBI RefSeq FAMs including TIGRFAMs',
25
+ },
26
+ {
27
+ name: 'SFLD',
28
+ category: FAMILIES,
29
+ description: 'Structure function linkage database',
30
+ },
31
+ {
32
+ name: 'Phobius',
33
+ category: FEATURES,
34
+ description:
35
+ 'A combined transmembrane topology and signal peptide predictor',
36
+ },
37
+ { name: 'SignalP', category: FEATURES },
38
+ { name: 'SignalP_EUK', category: OTHER },
39
+ { name: 'SignalP_GRAM_POSITIVE', category: OTHER },
40
+ { name: 'SignalP_GRAM_NEGATIVE', category: OTHER },
41
+ { name: 'SuperFamily', category: STRUCTURAL },
42
+ { name: 'Panther', category: FAMILIES },
43
+ { name: 'Gene3d', category: STRUCTURAL },
44
+ { name: 'HAMAP', category: FAMILIES },
45
+ { name: 'PrositeProfiles', category: FAMILIES },
46
+ { name: 'PrositePatterns', category: FAMILIES },
47
+ { name: 'Coils', category: FEATURES },
48
+ { name: 'SMART', category: FAMILIES },
49
+ {
50
+ name: 'CDD',
51
+ category: FAMILIES,
52
+ description: 'Conserved Domains Database',
53
+ },
54
+ { name: 'PRINTS', category: FAMILIES },
55
+ { name: 'PfamA', category: FAMILIES },
56
+ { name: 'MobiDBLite', category: FEATURES },
57
+ { name: 'PIRSF', category: OTHER },
58
+ { name: 'TMHMM', category: FEATURES },
59
+ { name: 'AntiFam', category: OTHER },
60
+ { name: 'FunFam', category: OTHER },
61
+ { name: 'PIRSR', category: FAMILIES },
62
+ ].map(program => ({ ...program, checked: true }))
63
+
13
64
  const InterProScanDialog = observer(function ({
14
65
  handleClose,
15
66
  model,
@@ -17,134 +68,7 @@ const InterProScanDialog = observer(function ({
17
68
  handleClose: () => void
18
69
  model: MsaViewModel
19
70
  }) {
20
- const [vals, setVals] = useState([
21
- {
22
- name: 'NCBIfam',
23
- description: 'NCBI RefSeq FAMs including TIGRFAMs',
24
- category: 'Families, domains, sites & repeats',
25
- checked: true,
26
- },
27
- {
28
- name: 'SFLD',
29
- description: 'Structure function linkage database',
30
- category: 'Families, domains, sites & repeats',
31
- checked: true,
32
- },
33
- {
34
- name: 'Phobius',
35
- checked: true,
36
- description:
37
- 'A combined transmembrane topology and signal peptide predictor',
38
- category: 'Other sequence features',
39
- },
40
- {
41
- name: 'SignalP',
42
- checked: true,
43
- category: 'Other sequence features',
44
- },
45
- {
46
- name: 'SignalP_EUK',
47
- category: 'Other category',
48
- checked: true,
49
- },
50
- {
51
- name: 'SignalP_GRAM_POSITIVE',
52
- category: 'Other category',
53
- checked: true,
54
- },
55
- {
56
- name: 'SignalP_GRAM_NEGATIVE',
57
- checked: true,
58
- category: 'Other category',
59
- },
60
- {
61
- name: 'SuperFamily',
62
- category: 'Structural domains',
63
- checked: true,
64
- },
65
- {
66
- name: 'Panther',
67
- category: 'Families, domains, sites & repeats',
68
- checked: true,
69
- },
70
- {
71
- name: 'Gene3d',
72
- category: 'Structural domains',
73
- checked: true,
74
- },
75
- {
76
- name: 'HAMAP',
77
- category: 'Families, domains, sites & repeats',
78
- checked: true,
79
- },
80
- {
81
- name: 'PrositeProfiles',
82
- category: 'Families, domains, sites & repeats',
83
- checked: true,
84
- },
85
- {
86
- name: 'PrositePatterns',
87
- category: 'Families, domains, sites & repeats',
88
- checked: true,
89
- },
90
- {
91
- name: 'Coils',
92
- category: 'Other sequence features',
93
- checked: true,
94
- },
95
- {
96
- name: 'SMART',
97
- category: 'Families, domains, sites & repeats',
98
- checked: true,
99
- },
100
- {
101
- name: 'CDD',
102
- description: 'Conserved Domains Database',
103
- category: 'Families, domains, sites & repeats',
104
- checked: true,
105
- },
106
- {
107
- name: 'PRINTS',
108
- category: 'Families, domains, sites & repeats',
109
- checked: true,
110
- },
111
- {
112
- name: 'PfamA',
113
- category: 'Families, domains, sites & repeats',
114
- checked: true,
115
- },
116
- {
117
- name: 'MobiDBLite',
118
- checked: true,
119
- category: 'Other sequence features',
120
- },
121
- {
122
- name: 'PIRSF',
123
- checked: true,
124
- category: 'Other category',
125
- },
126
- {
127
- name: 'TMHMM',
128
- checked: true,
129
- category: 'Other sequence features',
130
- },
131
-
132
- {
133
- name: 'AntiFam',
134
- checked: true,
135
- category: 'Other category',
136
- },
137
- {
138
- name: 'FunFam',
139
- checked: true,
140
- category: 'Other category',
141
- },
142
- {
143
- name: 'PIRSR',
144
- checked: true,
145
- category: 'Families, domains, sites & repeats',
146
- },
147
- ])
71
+ const [vals, setVals] = useState(interProScanPrograms)
148
72
 
149
73
  const programs = vals.filter(e => e.checked).map(e => e.name)
150
74
  const [show, setShow] = useState(false)
@@ -197,12 +121,11 @@ const InterProScanDialog = observer(function ({
197
121
  <tbody>
198
122
  {vals
199
123
  .toSorted((a, b) => a.category.localeCompare(b.category))
200
- .map(({ name, checked, category }) => (
124
+ .map(({ name, checked, category, description }) => (
201
125
  <tr key={name}>
202
126
  <td>
203
127
  <input
204
128
  type="checkbox"
205
- key={name}
206
129
  checked={checked}
207
130
  onChange={() => {
208
131
  setVals(
@@ -215,7 +138,7 @@ const InterProScanDialog = observer(function ({
215
138
  }}
216
139
  />
217
140
  </td>
218
- <td>{name}</td>
141
+ <td title={description}>{name}</td>
219
142
  <td>{category}</td>
220
143
  </tr>
221
144
  ))}
@@ -14,13 +14,14 @@ import {
14
14
  Typography,
15
15
  } from '@mui/material'
16
16
  import { observer } from 'mobx-react'
17
+ import { interProScanResponseToAnnotations } from 'msa-parsers'
17
18
 
18
19
  import { jsonfetch } from '../../fetchUtils.ts'
19
20
 
20
- import type { InterProScanResponse } from '../../launchInterProScan.ts'
21
21
  import type { MsaViewModel } from '../../model.ts'
22
+ import type { InterProScanResponse } from 'msa-parsers'
22
23
 
23
- const UserProvidedDomainsDialog = observer(function ({
24
+ const InterProScanFileDialog = observer(function ({
24
25
  handleClose,
25
26
  model,
26
27
  }: {
@@ -34,7 +35,7 @@ const UserProvidedDomainsDialog = observer(function ({
34
35
  return (
35
36
  <Dialog
36
37
  maxWidth="xl"
37
- title="Open protein domains from file"
38
+ title="Open InterProScan results"
38
39
  onClose={() => {
39
40
  handleClose()
40
41
  }}
@@ -112,16 +113,7 @@ const UserProvidedDomainsDialog = observer(function ({
112
113
  ? JSON.parse(await file.text())
113
114
  : await jsonfetch(interProURL)
114
115
 
115
- // key each result by its xref id; a result without one has no
116
- // row to attach to, and keying it `undefined` would draw a
117
- // phantom row's worth of domains
118
- model.setDomains(
119
- Object.fromEntries(
120
- ret.results
121
- .map(r => [r.xref[0]?.id, r] as const)
122
- .filter(e => e[0] !== undefined),
123
- ),
124
- )
116
+ model.setAnnotations(interProScanResponseToAnnotations(ret))
125
117
  getSession(model).notify(
126
118
  'Loaded interproscan results',
127
119
  'success',
@@ -143,4 +135,4 @@ const UserProvidedDomainsDialog = observer(function ({
143
135
  )
144
136
  })
145
137
 
146
- export default UserProvidedDomainsDialog
138
+ export default InterProScanFileDialog
@@ -1,11 +1,13 @@
1
- import React, { useState } from 'react'
1
+ import React from 'react'
2
2
 
3
3
  import { Dialog } from '@jbrowse/core/ui'
4
4
  import { makeStyles } from '@jbrowse/core/util/tss-react'
5
- import { Button, DialogActions, DialogContent } from '@mui/material'
5
+ import { Button, DialogActions, DialogContent, Typography } from '@mui/material'
6
6
  import { observer } from 'mobx-react'
7
7
 
8
- import copy from '../../vendor/copyToClipboard.ts'
8
+ import CopyButton from '../CopyButton.tsx'
9
+
10
+ import type { BasicTrack } from '../../types.ts'
9
11
 
10
12
  const useStyles = makeStyles()(theme => ({
11
13
  textArea: {
@@ -20,10 +22,10 @@ const TrackInfoDialog = observer(function ({
20
22
  model,
21
23
  onClose,
22
24
  }: {
23
- model: { name: string; data: string }
25
+ model: BasicTrack['model']
24
26
  onClose: () => void
25
27
  }) {
26
- const [label, setLabel] = useState('Copy to clipboard')
28
+ const { name, data } = model
27
29
  const { classes } = useStyles()
28
30
  return (
29
31
  <Dialog
@@ -31,23 +33,19 @@ const TrackInfoDialog = observer(function ({
31
33
  onClose={onClose}
32
34
  fullWidth
33
35
  maxWidth="lg"
34
- title={`Track info - ${model.name}`}
36
+ title={`Track info - ${name}`}
35
37
  >
36
38
  <DialogContent>
37
- <Button
38
- variant="contained"
39
- color="primary"
40
- onClick={() => {
41
- copy(model.data)
42
- setLabel('Copied!')
43
- setTimeout(() => {
44
- setLabel('Copy to clipboard')
45
- }, 300)
46
- }}
47
- >
48
- {label}
49
- </Button>
50
- <pre className={classes.textArea}>{model.data}</pre>
39
+ {/* the bar tracks (conservation) are computed per column and carry no
40
+ text of their own, so there is nothing to show or copy for them */}
41
+ {data === undefined ? (
42
+ <Typography>This track has no text data.</Typography>
43
+ ) : (
44
+ <>
45
+ <CopyButton text={data} />
46
+ <pre className={classes.textArea}>{data}</pre>
47
+ </>
48
+ )}
51
49
  </DialogContent>
52
50
  <DialogActions>
53
51
  <Button variant="contained" onClick={onClose} color="secondary">