react-msaview 5.9.0 → 6.0.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.
- package/bundle/index.js +99 -99
- package/bundle/index.js.map +4 -4
- package/dist/clustalX.js +22 -22
- package/dist/clustalX.js.map +1 -1
- package/dist/components/ConservationTrack.js +21 -16
- package/dist/components/ConservationTrack.js.map +1 -1
- package/dist/components/CopyButton.d.ts +9 -0
- package/dist/components/CopyButton.js +23 -0
- package/dist/components/CopyButton.js.map +1 -0
- package/dist/components/Loading.js +2 -2
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.js +18 -24
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.js +24 -40
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/ScrollbarThumb.d.ts +14 -0
- package/dist/components/ScrollbarThumb.js +28 -0
- package/dist/components/ScrollbarThumb.js.map +1 -0
- package/dist/components/SequenceTextArea.js +3 -10
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/TextTrack.js +26 -21
- package/dist/components/TextTrack.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +11 -25
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +3 -3
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/{UserProvidedDomainsDialog.d.ts → InterProScanFileDialog.d.ts} +2 -2
- package/dist/components/dialogs/{UserProvidedDomainsDialog.js → InterProScanFileDialog.js} +6 -10
- package/dist/components/dialogs/InterProScanFileDialog.js.map +1 -0
- package/dist/components/dialogs/TrackInfoDialog.d.ts +2 -4
- package/dist/components/dialogs/TrackInfoDialog.js +8 -14
- package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
- package/dist/components/header/FileMenu.js +3 -3
- package/dist/components/header/FileMenu.js.map +1 -1
- package/dist/components/header/GappynessSlider.js +1 -1
- package/dist/components/header/GappynessSlider.js.map +1 -1
- package/dist/components/header/{getDomainsMenu.d.ts → getAnnotationsMenu.d.ts} +1 -1
- package/dist/components/header/{getDomainsMenu.js → getAnnotationsMenu.js} +10 -9
- package/dist/components/header/getAnnotationsMenu.js.map +1 -0
- package/dist/components/header/settingsMenuItems.js +39 -72
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.js +66 -57
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/minimap/Minimap.js +11 -22
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.d.ts +2 -1
- package/dist/components/minimap/MinimapSVG.js +3 -4
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/minimap/minimapLayout.d.ts +10 -1
- package/dist/components/minimap/minimapLayout.js +15 -10
- package/dist/components/minimap/minimapLayout.js.map +1 -1
- package/dist/components/msa/{DomainLegend.d.ts → AnnotationLegend.d.ts} +2 -2
- package/dist/components/msa/{DomainLegend.js → AnnotationLegend.js} +4 -4
- package/dist/components/msa/AnnotationLegend.js.map +1 -0
- package/dist/components/msa/MSACanvas.js +2 -2
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +19 -16
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +14 -8
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/MSAPanel.js +2 -2
- package/dist/components/msa/MSAPanel.js.map +1 -1
- package/dist/components/msa/domainBandCursor.d.ts +17 -0
- package/dist/components/msa/domainBandCursor.js +39 -0
- package/dist/components/msa/domainBandCursor.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +9 -6
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +14 -20
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +32 -33
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/overlayColors.d.ts +2 -0
- package/dist/components/overlayColors.js +5 -0
- package/dist/components/overlayColors.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +29 -24
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +19 -12
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeRuler.js +5 -2
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +0 -38
- package/dist/components/tree/renderTreeCanvas.js +17 -17
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/ggplotPalettes.d.ts +0 -1
- package/dist/ggplotPalettes.js +0 -3
- package/dist/ggplotPalettes.js.map +1 -1
- package/dist/hierarchy.d.ts +2 -6
- package/dist/hierarchy.js +4 -6
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/launchInterProScan.d.ts +0 -23
- package/dist/launchInterProScan.js +2 -5
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/measureTextCanvas.js +21 -6
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model.d.ts +50 -100
- package/dist/model.js +209 -219
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.js +12 -19
- package/dist/neighborJoining.js.map +1 -1
- package/dist/parseAsn1.js +32 -43
- package/dist/parseAsn1.js.map +1 -1
- package/dist/renderToSvg.js +5 -2
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +13 -17
- package/dist/rowCoordinateCalculations.js +45 -39
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/seqPosToGlobalCol.d.ts +6 -19
- package/dist/seqPosToGlobalCol.js +6 -33
- package/dist/seqPosToGlobalCol.js.map +1 -1
- package/dist/types.d.ts +4 -11
- package/dist/useCanvasAutorun.d.ts +23 -1
- package/dist/useCanvasAutorun.js +20 -8
- package/dist/useCanvasAutorun.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/src/clustalX.ts +22 -22
- package/src/colSpace.test.ts +27 -0
- package/src/components/ConservationTrack.tsx +7 -5
- package/src/components/CopyButton.tsx +44 -0
- package/src/components/Loading.tsx +10 -1
- package/src/components/MSAView.tsx +25 -32
- package/src/components/ResizeHandles.tsx +60 -69
- package/src/components/ScrollbarThumb.tsx +48 -0
- package/src/components/SequenceTextArea.tsx +3 -16
- package/src/components/TextTrack.tsx +7 -12
- package/src/components/VerticalScrollbar.tsx +19 -33
- package/src/components/dialogs/FeatureDialog.tsx +3 -4
- package/src/components/dialogs/{UserProvidedDomainsDialog.tsx → InterProScanFileDialog.tsx} +6 -14
- package/src/components/dialogs/TrackInfoDialog.tsx +18 -20
- package/src/components/header/FileMenu.tsx +3 -3
- package/src/components/header/GappynessSlider.tsx +4 -1
- package/src/components/header/{getDomainsMenu.ts → getAnnotationsMenu.ts} +10 -9
- package/src/components/header/settingsMenuItems.ts +40 -72
- package/src/components/import/ImportForm.tsx +1 -1
- package/src/components/import/ImportFormExamples.tsx +82 -133
- package/src/components/minimap/Minimap.tsx +23 -31
- package/src/components/minimap/MinimapSVG.tsx +32 -31
- package/src/components/minimap/minimapLayout.test.ts +60 -0
- package/src/components/minimap/minimapLayout.ts +15 -10
- package/src/components/msa/{DomainLegend.tsx → AnnotationLegend.tsx} +7 -3
- package/src/components/msa/MSACanvas.tsx +3 -10
- package/src/components/msa/MSACanvasBlock.tsx +16 -21
- package/src/components/msa/MSAMouseoverCanvas.tsx +11 -9
- package/src/components/msa/MSAPanel.tsx +2 -2
- package/src/components/msa/domainBandCursor.ts +41 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +51 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +13 -8
- package/src/components/msa/renderMSABlock.ts +19 -23
- package/src/components/msa/renderMSAMouseover.ts +38 -35
- package/src/components/overlayColors.ts +6 -0
- package/src/components/tree/TreeCanvas.tsx +6 -4
- package/src/components/tree/TreeCanvasBlock.tsx +11 -12
- package/src/components/tree/TreeRuler.tsx +7 -2
- package/src/components/tree/renderTreeCanvas.test.ts +15 -7
- package/src/components/tree/renderTreeCanvas.ts +20 -17
- package/src/domainBands.test.ts +24 -0
- package/src/domainLetterColor.test.ts +80 -0
- package/src/ggplotPalettes.ts +0 -4
- package/src/hierarchy.test.ts +7 -7
- package/src/hierarchy.ts +6 -9
- package/src/index.ts +4 -1
- package/src/largeTree.test.ts +23 -2
- package/src/launchInterProScan.ts +3 -30
- package/src/loadErrorDisplay.test.tsx +102 -0
- package/src/measureTextCanvas.ts +22 -6
- package/src/model.ts +233 -244
- package/src/modelFilehandleLoaders.test.ts +137 -0
- package/src/neighborJoining.test.ts +12 -0
- package/src/neighborJoining.ts +12 -20
- package/src/parseAsn1.ts +32 -40
- package/src/{renderDomainLegendSvg.test.tsx → renderDomainsSvg.test.tsx} +44 -20
- package/src/renderMinimapSvg.test.tsx +109 -0
- package/src/renderToSvg.tsx +5 -2
- package/src/rowCoordinateCalculations.ts +48 -44
- package/src/seqPosToGlobalCol.test.ts +39 -51
- package/src/seqPosToGlobalCol.ts +6 -41
- package/src/types.ts +10 -15
- package/src/useCanvasAutorun.test.tsx +98 -0
- package/src/useCanvasAutorun.ts +30 -11
- package/src/version.ts +1 -1
- package/src/viewChrome.test.tsx +134 -0
- package/dist/components/dialogs/DomainDialog.d.ts +0 -6
- package/dist/components/dialogs/DomainDialog.js +0 -19
- package/dist/components/dialogs/DomainDialog.js.map +0 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +0 -1
- package/dist/components/header/SettingsMenu.d.ts +0 -6
- package/dist/components/header/SettingsMenu.js +0 -40
- package/dist/components/header/SettingsMenu.js.map +0 -1
- package/dist/components/header/getDomainsMenu.js.map +0 -1
- package/dist/components/msa/DomainLegend.js.map +0 -1
- package/src/components/dialogs/DomainDialog.tsx +0 -45
- package/src/components/header/SettingsMenu.tsx +0 -57
|
@@ -9,27 +9,29 @@ import type { MsaViewModel } from '../model.ts'
|
|
|
9
9
|
const handleBg = 'rgba(200,200,200)'
|
|
10
10
|
const handleBgHover = 'rgba(150,150,150)'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A draggable divider. `getStart` is read at mousedown and handed back to
|
|
14
|
+
* `onDrag` alongside the pixel delta since, so each handle below only has to say
|
|
15
|
+
* which model dimension it resizes and where it sits.
|
|
16
|
+
*/
|
|
17
|
+
function ResizeHandle({
|
|
18
|
+
axis,
|
|
19
|
+
getStart,
|
|
20
|
+
onDrag,
|
|
21
|
+
style,
|
|
14
22
|
}: {
|
|
15
|
-
|
|
23
|
+
axis: 'x' | 'y'
|
|
24
|
+
getStart: () => number
|
|
25
|
+
onDrag: (delta: number, startValue: number) => void
|
|
26
|
+
style: React.CSSProperties
|
|
16
27
|
}) {
|
|
17
|
-
const { resizeHandleWidth } = model
|
|
18
28
|
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
|
-
),
|
|
27
|
-
)
|
|
29
|
+
const { startDrag } = useDragScroll(axis, onDrag)
|
|
28
30
|
|
|
29
31
|
return (
|
|
30
32
|
<div
|
|
31
33
|
onMouseDown={event => {
|
|
32
|
-
startDrag(event,
|
|
34
|
+
startDrag(event, getStart())
|
|
33
35
|
}}
|
|
34
36
|
onMouseEnter={() => {
|
|
35
37
|
setHovered(true)
|
|
@@ -38,13 +40,34 @@ export const VerticalResizeHandle = observer(function ({
|
|
|
38
40
|
setHovered(false)
|
|
39
41
|
}}
|
|
40
42
|
style={{
|
|
41
|
-
cursor: 'ew-resize',
|
|
42
|
-
width: resizeHandleWidth,
|
|
43
|
-
background: hovered ? handleBgHover : handleBg,
|
|
44
43
|
position: 'relative',
|
|
44
|
+
cursor: axis === 'x' ? 'ew-resize' : 'ns-resize',
|
|
45
|
+
background: hovered ? handleBgHover : handleBg,
|
|
46
|
+
...style,
|
|
45
47
|
}}
|
|
46
48
|
/>
|
|
47
49
|
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const VerticalResizeHandle = observer(function ({
|
|
53
|
+
model,
|
|
54
|
+
}: {
|
|
55
|
+
model: MsaViewModel
|
|
56
|
+
}) {
|
|
57
|
+
const onDrag = useCallback(
|
|
58
|
+
(delta: number, startWidth: number) => {
|
|
59
|
+
model.setTreeAreaWidth(startWidth + delta)
|
|
60
|
+
},
|
|
61
|
+
[model],
|
|
62
|
+
)
|
|
63
|
+
return (
|
|
64
|
+
<ResizeHandle
|
|
65
|
+
axis="x"
|
|
66
|
+
getStart={() => model.treeAreaWidth}
|
|
67
|
+
onDrag={onDrag}
|
|
68
|
+
style={{ width: model.resizeHandleWidth }}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
48
71
|
})
|
|
49
72
|
|
|
50
73
|
export const HorizontalResizeHandle = observer(function ({
|
|
@@ -52,36 +75,18 @@ export const HorizontalResizeHandle = observer(function ({
|
|
|
52
75
|
}: {
|
|
53
76
|
model: MsaViewModel
|
|
54
77
|
}) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(delta: number, startHeight: number) => {
|
|
61
|
-
model.setHeight(startHeight + delta)
|
|
62
|
-
},
|
|
63
|
-
[model],
|
|
64
|
-
),
|
|
78
|
+
const onDrag = useCallback(
|
|
79
|
+
(delta: number, startHeight: number) => {
|
|
80
|
+
model.setHeight(startHeight + delta)
|
|
81
|
+
},
|
|
82
|
+
[model],
|
|
65
83
|
)
|
|
66
|
-
|
|
67
84
|
return (
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
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
|
-
}}
|
|
85
|
+
<ResizeHandle
|
|
86
|
+
axis="y"
|
|
87
|
+
getStart={() => model.height}
|
|
88
|
+
onDrag={onDrag}
|
|
89
|
+
style={{ width: '100%', height: model.resizeHandleWidth }}
|
|
85
90
|
/>
|
|
86
91
|
)
|
|
87
92
|
})
|
|
@@ -91,38 +96,24 @@ export const ConservationTrackResizeHandle = observer(function ({
|
|
|
91
96
|
}: {
|
|
92
97
|
model: MsaViewModel
|
|
93
98
|
}) {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
(delta: number, startHeight: number) => {
|
|
100
|
-
model.setConservationTrackHeight(Math.max(10, startHeight + delta))
|
|
101
|
-
},
|
|
102
|
-
[model],
|
|
103
|
-
),
|
|
99
|
+
const onDrag = useCallback(
|
|
100
|
+
(delta: number, startHeight: number) => {
|
|
101
|
+
model.setConservationTrackHeight(Math.max(10, startHeight + delta))
|
|
102
|
+
},
|
|
103
|
+
[model],
|
|
104
104
|
)
|
|
105
|
-
|
|
106
105
|
return (
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
onMouseEnter={() => {
|
|
112
|
-
setHovered(true)
|
|
113
|
-
}}
|
|
114
|
-
onMouseLeave={() => {
|
|
115
|
-
setHovered(false)
|
|
116
|
-
}}
|
|
106
|
+
<ResizeHandle
|
|
107
|
+
axis="y"
|
|
108
|
+
getStart={() => model.conservationTrackHeight}
|
|
109
|
+
onDrag={onDrag}
|
|
117
110
|
style={{
|
|
118
111
|
position: 'absolute',
|
|
119
112
|
bottom: 0,
|
|
120
113
|
left: 0,
|
|
121
|
-
cursor: 'ns-resize',
|
|
122
114
|
width: '100%',
|
|
123
|
-
height: resizeHandleWidth,
|
|
115
|
+
height: model.resizeHandleWidth,
|
|
124
116
|
zIndex: 1,
|
|
125
|
-
background: hovered ? handleBgHover : handleBg,
|
|
126
117
|
}}
|
|
127
118
|
/>
|
|
128
119
|
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { useDragScroll } from '../useDragScroll.ts'
|
|
4
|
+
|
|
5
|
+
export const scrollbarThumbFill = 'rgba(66,119,127,0.3)'
|
|
6
|
+
const scrollbarThumbFillHovered = 'rgba(66,119,127,0.6)'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The draggable thumb shared by the horizontal Minimap and the
|
|
10
|
+
* VerticalScrollbar. `getStart` is read at mousedown and handed back to
|
|
11
|
+
* `onDrag` alongside the pixel delta since, so a caller only supplies the
|
|
12
|
+
* scroll offset it drives and where the thumb sits.
|
|
13
|
+
*/
|
|
14
|
+
export default function ScrollbarThumb({
|
|
15
|
+
axis,
|
|
16
|
+
getStart,
|
|
17
|
+
onDrag,
|
|
18
|
+
style,
|
|
19
|
+
}: {
|
|
20
|
+
axis: 'x' | 'y'
|
|
21
|
+
getStart: () => number
|
|
22
|
+
onDrag: (delta: number, startValue: number) => void
|
|
23
|
+
style: React.CSSProperties
|
|
24
|
+
}) {
|
|
25
|
+
const [hovered, setHovered] = useState(false)
|
|
26
|
+
const { startDrag } = useDragScroll(axis, onDrag)
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
onMouseOver={() => {
|
|
31
|
+
setHovered(true)
|
|
32
|
+
}}
|
|
33
|
+
onMouseOut={() => {
|
|
34
|
+
setHovered(false)
|
|
35
|
+
}}
|
|
36
|
+
onMouseDown={event => {
|
|
37
|
+
startDrag(event, getStart())
|
|
38
|
+
}}
|
|
39
|
+
style={{
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
zIndex: 100,
|
|
42
|
+
cursor: 'pointer',
|
|
43
|
+
background: hovered ? scrollbarThumbFillHovered : scrollbarThumbFill,
|
|
44
|
+
...style,
|
|
45
|
+
}}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -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 {
|
|
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
|
-
<
|
|
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}
|
|
@@ -32,16 +32,9 @@ const AnnotationBlock = observer(function ({
|
|
|
32
32
|
|
|
33
33
|
const colorScheme = customColorScheme ?? modelColorScheme
|
|
34
34
|
const { theme, contrastScheme } = useColorContrast(colorScheme)
|
|
35
|
-
const ref = useCanvasAutorun(
|
|
36
|
-
ctx => {
|
|
37
|
-
const {
|
|
38
|
-
blockSize,
|
|
39
|
-
bgColor,
|
|
40
|
-
colWidth,
|
|
41
|
-
fontSize,
|
|
42
|
-
rowHeight,
|
|
43
|
-
highResScaleFactor,
|
|
44
|
-
} = model
|
|
35
|
+
const ref = useCanvasAutorun({
|
|
36
|
+
draw: ctx => {
|
|
37
|
+
const { bgColor, colWidth, fontSize } = model
|
|
45
38
|
ctx.resetTransform()
|
|
46
39
|
ctx.scale(highResScaleFactor, highResScaleFactor)
|
|
47
40
|
ctx.clearRect(0, 0, blockSize, rowHeight)
|
|
@@ -62,8 +55,10 @@ const AnnotationBlock = observer(function ({
|
|
|
62
55
|
blockSize,
|
|
63
56
|
})
|
|
64
57
|
},
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
width: blockSize * highResScaleFactor,
|
|
59
|
+
height: rowHeight * highResScaleFactor,
|
|
60
|
+
deps: [model, offsetX, theme, contrastScheme, colorScheme, data],
|
|
61
|
+
})
|
|
67
62
|
return (
|
|
68
63
|
<canvas
|
|
69
64
|
ref={ref}
|
|
@@ -1,61 +1,47 @@
|
|
|
1
|
-
import React, { useCallback
|
|
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
|
|
5
|
+
import ScrollbarThumb from './ScrollbarThumb.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
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
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
|
-
<
|
|
35
|
+
<ScrollbarThumb
|
|
36
|
+
axis="y"
|
|
37
|
+
getStart={() => model.scrollY}
|
|
38
|
+
onDrag={onDrag}
|
|
40
39
|
style={{
|
|
41
|
-
position: 'absolute',
|
|
42
40
|
top: Math.max(0, t),
|
|
43
41
|
left: 0,
|
|
44
|
-
background: hovered ? 'rgba(66,119,127,0.6)' : fill,
|
|
45
|
-
cursor: 'pointer',
|
|
46
42
|
boxSizing: 'border-box',
|
|
47
|
-
width
|
|
43
|
+
width,
|
|
48
44
|
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
45
|
}}
|
|
60
46
|
/>
|
|
61
47
|
</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 {
|
|
47
|
-
model
|
|
46
|
+
const { annotationTypes, annotations, fillPalette } = model
|
|
48
47
|
const counts = new Map<string, number>()
|
|
49
|
-
for (const annot of
|
|
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
|
-
{[...
|
|
66
|
+
{[...annotationTypes.values()].map(
|
|
68
67
|
({ accession, name, description }) => (
|
|
69
68
|
<TableRow key={accession}>
|
|
70
69
|
<TableCell padding="checkbox">
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
138
|
+
export default InterProScanFileDialog
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import 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
|
|
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:
|
|
25
|
+
model: BasicTrack['model']
|
|
24
26
|
onClose: () => void
|
|
25
27
|
}) {
|
|
26
|
-
const
|
|
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 - ${
|
|
36
|
+
title={`Track info - ${name}`}
|
|
35
37
|
>
|
|
36
38
|
<DialogContent>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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">
|
|
@@ -7,7 +7,7 @@ import Menu from '@mui/icons-material/Menu'
|
|
|
7
7
|
import PhotoCamera from '@mui/icons-material/PhotoCamera'
|
|
8
8
|
import { observer } from 'mobx-react'
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { getAnnotationsMenu } from './getAnnotationsMenu.ts'
|
|
11
11
|
|
|
12
12
|
import type { MsaViewModel } from '../../model.ts'
|
|
13
13
|
|
|
@@ -41,9 +41,9 @@ const FileMenu = observer(({ model }: { model: MsaViewModel }) => {
|
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
label: '
|
|
44
|
+
label: 'Annotations',
|
|
45
45
|
type: 'subMenu',
|
|
46
|
-
subMenu:
|
|
46
|
+
subMenu: getAnnotationsMenu({
|
|
47
47
|
model,
|
|
48
48
|
}),
|
|
49
49
|
},
|
|
@@ -16,8 +16,11 @@ const GappynessSlider = observer(function GappynessSlider({
|
|
|
16
16
|
}
|
|
17
17
|
return (
|
|
18
18
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
19
|
+
{/* the threshold is inclusive: blanks are columns whose gap count is at
|
|
20
|
+
least ceil(allowedGappyness% of the rows), so at 100 it hides the
|
|
21
|
+
columns that are entirely gaps rather than nothing */}
|
|
19
22
|
<Typography style={{ whiteSpace: 'nowrap' }}>
|
|
20
|
-
Hide columns w/ &
|
|
23
|
+
Hide columns w/ ≥{allowedGappyness}% gaps
|
|
21
24
|
</Typography>
|
|
22
25
|
<Slider
|
|
23
26
|
// Named, because the class alone is not enough to find it from outside.
|
|
@@ -9,22 +9,23 @@ import Visibility from '@mui/icons-material/Visibility'
|
|
|
9
9
|
import type { MsaViewModel } from '../../model.ts'
|
|
10
10
|
|
|
11
11
|
const FeatureFilterDialog = lazy(() => import('../dialogs/FeatureDialog.tsx'))
|
|
12
|
-
const
|
|
13
|
-
() => import('../dialogs/
|
|
12
|
+
const InterProScanFileDialog = lazy(
|
|
13
|
+
() => import('../dialogs/InterProScanFileDialog.tsx'),
|
|
14
14
|
)
|
|
15
15
|
const InterProScanDialog = lazy(
|
|
16
16
|
() => import('../dialogs/InterProScanDialog.tsx'),
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
-
export function
|
|
19
|
+
export function getAnnotationsMenu({ model }: { model: MsaViewModel }) {
|
|
20
20
|
const { showDomains, actuallyShowDomains, subFeatureRows, noDomains } = model
|
|
21
|
+
const noneLoaded = noDomains ? ' (none loaded)' : ''
|
|
21
22
|
return [
|
|
22
23
|
{
|
|
23
|
-
label: 'Open
|
|
24
|
+
label: 'Open InterProScan results...',
|
|
24
25
|
icon: FolderOpen,
|
|
25
26
|
onClick: () => {
|
|
26
27
|
model.queueDialog(handleClose => [
|
|
27
|
-
|
|
28
|
+
InterProScanFileDialog,
|
|
28
29
|
{
|
|
29
30
|
handleClose,
|
|
30
31
|
model,
|
|
@@ -33,7 +34,7 @@ export function getDomainMenu({ model }: { model: MsaViewModel }) {
|
|
|
33
34
|
},
|
|
34
35
|
},
|
|
35
36
|
{
|
|
36
|
-
label: 'Query InterProScan
|
|
37
|
+
label: 'Query InterProScan...',
|
|
37
38
|
icon: Search,
|
|
38
39
|
onClick: () => {
|
|
39
40
|
model.queueDialog(handleClose => [
|
|
@@ -46,7 +47,7 @@ export function getDomainMenu({ model }: { model: MsaViewModel }) {
|
|
|
46
47
|
},
|
|
47
48
|
},
|
|
48
49
|
{
|
|
49
|
-
label: `Show
|
|
50
|
+
label: `Show annotations${noneLoaded}`,
|
|
50
51
|
disabled: noDomains,
|
|
51
52
|
icon: Visibility,
|
|
52
53
|
checked: actuallyShowDomains,
|
|
@@ -56,7 +57,7 @@ export function getDomainMenu({ model }: { model: MsaViewModel }) {
|
|
|
56
57
|
},
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
|
-
label: `Use sub-row layout${
|
|
60
|
+
label: `Use sub-row layout${noneLoaded}`,
|
|
60
61
|
disabled: noDomains,
|
|
61
62
|
checked: actuallyShowDomains ? subFeatureRows : false,
|
|
62
63
|
icon: Sort,
|
|
@@ -66,7 +67,7 @@ export function getDomainMenu({ model }: { model: MsaViewModel }) {
|
|
|
66
67
|
},
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
|
-
label: `Filter
|
|
70
|
+
label: `Filter annotations${noneLoaded}`,
|
|
70
71
|
icon: FilterAlt,
|
|
71
72
|
disabled: noDomains,
|
|
72
73
|
onClick: () => {
|