react-msaview 3.1.12 → 3.2.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 +32 -31
- package/dist/colorSchemes.d.ts +2 -2
- package/dist/colorSchemes.js +3 -4
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/Loading.d.ts +1 -1
- package/dist/components/Loading.js +4 -4
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.d.ts +1 -1
- package/dist/components/MSAView.js +13 -9
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +1 -1
- package/dist/components/ResizeHandles.js +2 -2
- package/dist/components/TextTrack.d.ts +1 -1
- package/dist/components/Track.d.ts +1 -1
- package/dist/components/VerticalScrollbar.d.ts +6 -0
- package/dist/components/VerticalScrollbar.js +65 -0
- package/dist/components/VerticalScrollbar.js.map +1 -0
- package/dist/components/dialogs/AddTrackDialog.d.ts +1 -1
- package/dist/components/dialogs/DomainDialog.d.ts +1 -1
- package/dist/components/dialogs/DomainDialog.js +2 -2
- package/dist/components/dialogs/DomainDialog.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/{InterProScanPanel.d.ts → InterProScanDialog.d.ts} +1 -1
- package/dist/components/dialogs/{InterProScanPanel.js → InterProScanDialog.js} +4 -3
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -0
- package/dist/components/dialogs/MetadataDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.js +10 -1
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/components/dialogs/TracklistDialog.d.ts +1 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.d.ts +7 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js +58 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -0
- package/dist/components/header/Header.d.ts +1 -1
- package/dist/components/header/Header.js +8 -3
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderInfoArea.d.ts +1 -1
- package/dist/components/header/HeaderMenu.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.js +30 -28
- package/dist/components/header/HeaderMenuExtra.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.d.ts +2 -2
- package/dist/components/header/HeaderStatusArea.js +1 -1
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/MultiAlignmentSelector.d.ts +1 -1
- package/dist/components/header/ZoomControls.js +31 -1
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/import/ImportForm.d.ts +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.d.ts +1 -1
- package/dist/components/import/ImportFormExamples.js +10 -8
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.d.ts +2 -2
- package/dist/components/minimap/Minimap.d.ts +1 -1
- package/dist/components/minimap/Minimap.js +14 -15
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.d.ts +1 -1
- package/dist/components/minimap/MinimapSVG.js +1 -1
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/msa/MSACanvas.d.ts +1 -1
- package/dist/components/msa/MSACanvas.js +3 -3
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.d.ts +3 -3
- package/dist/components/msa/MSACanvasBlock.js +4 -3
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.d.ts +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/MSAPanel.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +1 -2
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +2 -2
- package/dist/components/msa/renderMSABlock.js +12 -12
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.d.ts +1 -1
- package/dist/components/tree/TreeBranchMenu.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.js +13 -12
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.d.ts +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -1
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeNodeMenu.d.ts +1 -1
- package/dist/components/tree/TreeNodeMenu.js +2 -2
- package/dist/components/tree/TreeNodeMenu.js.map +1 -1
- package/dist/components/tree/TreePanel.d.ts +1 -1
- package/dist/components/tree/TreeRuler.d.ts +1 -1
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +3 -3
- package/dist/components/tree/renderTreeCanvas.js +25 -9
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/util.js +1 -1
- package/dist/components/util.js.map +1 -1
- package/dist/launchInterProScan.d.ts +1 -1
- package/dist/launchInterProScan.js +7 -9
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/model/DataModel.d.ts +5 -1
- package/dist/model/DataModel.js +10 -1
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/DialogQueue.d.ts +1 -1
- package/dist/model.d.ts +141 -24
- package/dist/model.js +236 -50
- package/dist/model.js.map +1 -1
- package/dist/parseNewick.js +1 -1
- package/dist/parseNewick.js.map +1 -1
- package/dist/parsers/ClustalMSA.d.ts +1 -1
- package/dist/parsers/FastaMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.js.map +1 -1
- package/dist/renderToSvg.d.ts +2 -2
- package/dist/renderToSvg.js +3 -5
- package/dist/renderToSvg.js.map +1 -1
- package/dist/reparseTree.d.ts +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.js +0 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +5 -2
- package/src/colorSchemes.ts +3 -2
- package/src/components/Checkbox2.tsx +1 -1
- package/src/components/Loading.tsx +11 -5
- package/src/components/MSAView.tsx +27 -18
- package/src/components/ResizeHandles.tsx +3 -3
- package/src/components/TextTrack.tsx +1 -1
- package/src/components/Track.tsx +1 -1
- package/src/components/VerticalScrollbar.tsx +85 -0
- package/src/components/dialogs/AddTrackDialog.tsx +2 -2
- package/src/components/dialogs/DomainDialog.tsx +3 -3
- package/src/components/dialogs/ExportSVGDialog.tsx +1 -1
- package/src/components/dialogs/FeatureDialog.tsx +3 -3
- package/src/components/dialogs/{InterProScanPanel.tsx → InterProScanDialog.tsx} +11 -4
- package/src/components/dialogs/MetadataDialog.tsx +1 -1
- package/src/components/dialogs/SettingsDialog.tsx +38 -3
- package/src/components/dialogs/TracklistDialog.tsx +1 -1
- package/src/components/dialogs/UserProvidedDomainsDialog.tsx +133 -0
- package/src/components/header/Header.tsx +9 -4
- package/src/components/header/HeaderInfoArea.tsx +1 -1
- package/src/components/header/HeaderMenu.tsx +1 -1
- package/src/components/header/HeaderMenuExtra.tsx +36 -32
- package/src/components/header/HeaderStatusArea.tsx +2 -6
- package/src/components/header/MultiAlignmentSelector.tsx +1 -1
- package/src/components/header/ZoomControls.tsx +34 -0
- package/src/components/import/ImportForm.tsx +3 -3
- package/src/components/import/ImportFormExamples.tsx +19 -17
- package/src/components/import/util.ts +2 -2
- package/src/components/minimap/Minimap.tsx +15 -22
- package/src/components/minimap/MinimapSVG.tsx +2 -2
- package/src/components/msa/MSACanvas.tsx +11 -4
- package/src/components/msa/MSACanvasBlock.tsx +5 -4
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -6
- package/src/components/msa/MSAPanel.tsx +1 -1
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +4 -5
- package/src/components/msa/renderMSABlock.ts +37 -17
- package/src/components/msa/renderMSAMouseover.ts +1 -1
- package/src/components/tree/TreeBranchMenu.tsx +1 -1
- package/src/components/tree/TreeCanvas.tsx +15 -16
- package/src/components/tree/TreeCanvasBlock.tsx +3 -2
- package/src/components/tree/TreeNodeMenu.tsx +3 -3
- package/src/components/tree/TreePanel.tsx +1 -1
- package/src/components/tree/TreeRuler.tsx +1 -1
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +1 -1
- package/src/components/tree/renderTreeCanvas.ts +32 -12
- package/src/components/util.ts +1 -1
- package/src/launchInterProScan.ts +8 -10
- package/src/model/DataModel.ts +10 -0
- package/src/model/DialogQueue.ts +1 -1
- package/src/model.ts +262 -62
- package/src/parseNewick.ts +1 -1
- package/src/parsers/ClustalMSA.ts +1 -1
- package/src/parsers/FastaMSA.ts +1 -1
- package/src/parsers/StockholmMSA.ts +1 -1
- package/src/renderToSvg.tsx +6 -6
- package/src/reparseTree.ts +1 -1
- package/src/util.ts +2 -4
- package/src/version.ts +1 -1
- package/dist/components/dialogs/InterProScanPanel.js.map +0 -1
- package/dist/components/dialogs/UserProvidedResultPanel.d.ts +0 -7
- package/dist/components/dialogs/UserProvidedResultPanel.js +0 -56
- package/dist/components/dialogs/UserProvidedResultPanel.js.map +0 -1
- package/src/components/dialogs/UserProvidedResultPanel.tsx +0 -119
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
Typography,
|
|
13
13
|
} from '@mui/material'
|
|
14
14
|
|
|
15
|
-
import { MsaViewModel } from '../../model'
|
|
15
|
+
import type { MsaViewModel } from '../../model'
|
|
16
16
|
import colorSchemes from '../../colorSchemes'
|
|
17
17
|
import Checkbox2 from '../Checkbox2'
|
|
18
18
|
|
|
@@ -115,17 +115,40 @@ const MSASettings = observer(function MSASettings({
|
|
|
115
115
|
model: MsaViewModel
|
|
116
116
|
}) {
|
|
117
117
|
const { classes } = useStyles()
|
|
118
|
-
const {
|
|
118
|
+
const {
|
|
119
|
+
bgColor,
|
|
120
|
+
contrastLettering,
|
|
121
|
+
colWidth,
|
|
122
|
+
allowedGappyness,
|
|
123
|
+
drawMsaLetters,
|
|
124
|
+
colorSchemeName,
|
|
125
|
+
hideGaps,
|
|
126
|
+
rowHeight,
|
|
127
|
+
} = model
|
|
119
128
|
|
|
120
129
|
return (
|
|
121
130
|
<div>
|
|
122
131
|
<h1>MSA options</h1>
|
|
123
|
-
|
|
132
|
+
<Checkbox2
|
|
133
|
+
checked={drawMsaLetters}
|
|
134
|
+
onChange={() => model.setDrawMsaLetters(!drawMsaLetters)}
|
|
135
|
+
label="Draw letters"
|
|
136
|
+
/>
|
|
124
137
|
<Checkbox2
|
|
125
138
|
checked={bgColor}
|
|
126
139
|
onChange={() => model.setBgColor(!bgColor)}
|
|
127
140
|
label="Color background tiles of MSA?"
|
|
128
141
|
/>
|
|
142
|
+
<Checkbox2
|
|
143
|
+
checked={contrastLettering}
|
|
144
|
+
onChange={() => model.setContrastLettering(!contrastLettering)}
|
|
145
|
+
label="Use contrast lettering"
|
|
146
|
+
/>
|
|
147
|
+
<Checkbox2
|
|
148
|
+
checked={hideGaps}
|
|
149
|
+
onChange={() => model.setHideGaps(!hideGaps)}
|
|
150
|
+
label={`Hide columns that are ${100 - allowedGappyness}% gaps`}
|
|
151
|
+
/>
|
|
129
152
|
|
|
130
153
|
<div className={classes.flex}>
|
|
131
154
|
<Typography>Column width ({colWidth}px)</Typography>
|
|
@@ -147,6 +170,18 @@ const MSASettings = observer(function MSASettings({
|
|
|
147
170
|
onChange={(_, val) => model.setRowHeight(val as number)}
|
|
148
171
|
/>
|
|
149
172
|
</div>
|
|
173
|
+
{hideGaps ? (
|
|
174
|
+
<div className={classes.flex}>
|
|
175
|
+
<Typography>Allowed gappyness ({100 - allowedGappyness}%)</Typography>
|
|
176
|
+
<Slider
|
|
177
|
+
className={classes.field}
|
|
178
|
+
min={1}
|
|
179
|
+
max={100}
|
|
180
|
+
value={allowedGappyness}
|
|
181
|
+
onChange={(_, val) => model.setAllowedGappyness(val as number)}
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
) : null}
|
|
150
185
|
|
|
151
186
|
<TextField
|
|
152
187
|
select
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { observer } from 'mobx-react'
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
DialogActions,
|
|
6
|
+
DialogContent,
|
|
7
|
+
FormControlLabel,
|
|
8
|
+
FormControl,
|
|
9
|
+
Radio,
|
|
10
|
+
RadioGroup,
|
|
11
|
+
TextField,
|
|
12
|
+
Typography,
|
|
13
|
+
} from '@mui/material'
|
|
14
|
+
import { getSession } from '@jbrowse/core/util'
|
|
15
|
+
import { Dialog } from '@jbrowse/core/ui'
|
|
16
|
+
|
|
17
|
+
// locals
|
|
18
|
+
import type { MsaViewModel } from '../../model'
|
|
19
|
+
import { jsonfetch } from '../../fetchUtils'
|
|
20
|
+
import type { InterProScanResponse } from '../../launchInterProScan'
|
|
21
|
+
|
|
22
|
+
const UserProvidedDomainsDialog = observer(function ({
|
|
23
|
+
handleClose,
|
|
24
|
+
model,
|
|
25
|
+
}: {
|
|
26
|
+
handleClose: () => void
|
|
27
|
+
model: MsaViewModel
|
|
28
|
+
}) {
|
|
29
|
+
const [file, setFile] = useState<File>()
|
|
30
|
+
const [choice, setChoice] = useState('file')
|
|
31
|
+
const [interProURL, setInterProURL] = useState('')
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Dialog
|
|
35
|
+
maxWidth="xl"
|
|
36
|
+
title="Open protein domains from file"
|
|
37
|
+
onClose={() => handleClose()}
|
|
38
|
+
open
|
|
39
|
+
>
|
|
40
|
+
<DialogContent>
|
|
41
|
+
<div>
|
|
42
|
+
<Typography>
|
|
43
|
+
Open a JSON file of InterProScan results that you run remotely on
|
|
44
|
+
EBI servers or locally
|
|
45
|
+
</Typography>
|
|
46
|
+
|
|
47
|
+
<div style={{ display: 'flex', margin: 30 }}>
|
|
48
|
+
<FormControl component="fieldset">
|
|
49
|
+
<RadioGroup
|
|
50
|
+
value={choice}
|
|
51
|
+
onChange={event => setChoice(event.target.value)}
|
|
52
|
+
>
|
|
53
|
+
<FormControlLabel value="url" control={<Radio />} label="URL" />
|
|
54
|
+
<FormControlLabel
|
|
55
|
+
value="file"
|
|
56
|
+
control={<Radio />}
|
|
57
|
+
label="File"
|
|
58
|
+
/>
|
|
59
|
+
</RadioGroup>
|
|
60
|
+
</FormControl>
|
|
61
|
+
{choice === 'url' ? (
|
|
62
|
+
<div>
|
|
63
|
+
<Typography>
|
|
64
|
+
Open a InterProScan JSON file remote URL
|
|
65
|
+
</Typography>
|
|
66
|
+
<TextField
|
|
67
|
+
label="URL"
|
|
68
|
+
value={interProURL}
|
|
69
|
+
onChange={event => setInterProURL(event.target.value)}
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
) : null}
|
|
73
|
+
{choice === 'file' ? (
|
|
74
|
+
<div style={{ paddingTop: 20 }}>
|
|
75
|
+
<Typography>
|
|
76
|
+
Open a InterProScan JSON file file from your local drive
|
|
77
|
+
</Typography>
|
|
78
|
+
<Button variant="outlined" component="label">
|
|
79
|
+
Choose File
|
|
80
|
+
<input
|
|
81
|
+
type="file"
|
|
82
|
+
hidden
|
|
83
|
+
onChange={({ target }) => {
|
|
84
|
+
const file = target?.files?.[0]
|
|
85
|
+
if (file) {
|
|
86
|
+
setFile(file)
|
|
87
|
+
}
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
</Button>
|
|
91
|
+
</div>
|
|
92
|
+
) : null}
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</DialogContent>
|
|
96
|
+
<DialogActions>
|
|
97
|
+
<Button
|
|
98
|
+
variant="contained"
|
|
99
|
+
color="primary"
|
|
100
|
+
onClick={() => {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
102
|
+
;(async () => {
|
|
103
|
+
try {
|
|
104
|
+
const ret: InterProScanResponse = file
|
|
105
|
+
? JSON.parse(await file.text())
|
|
106
|
+
: await jsonfetch(interProURL)
|
|
107
|
+
|
|
108
|
+
model.setInterProAnnotations(
|
|
109
|
+
Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
|
|
110
|
+
)
|
|
111
|
+
model.setShowDomains(true)
|
|
112
|
+
getSession(model).notify(
|
|
113
|
+
'Loaded interproscan results',
|
|
114
|
+
'success',
|
|
115
|
+
)
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.error(e)
|
|
118
|
+
getSession(model).notifyError(`${e}`, e)
|
|
119
|
+
} finally {
|
|
120
|
+
model.setStatus()
|
|
121
|
+
}
|
|
122
|
+
})()
|
|
123
|
+
handleClose()
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
Open results
|
|
127
|
+
</Button>
|
|
128
|
+
</DialogActions>
|
|
129
|
+
</Dialog>
|
|
130
|
+
)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
export default UserProvidedDomainsDialog
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React, { lazy } from 'react'
|
|
1
|
+
import React, { lazy, useEffect } from 'react'
|
|
2
2
|
import { IconButton } from '@mui/material'
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
|
+
import useMeasure from '@jbrowse/core/util/useMeasure'
|
|
4
5
|
|
|
5
6
|
// locals
|
|
6
|
-
import { MsaViewModel } from '../../model'
|
|
7
|
+
import type { MsaViewModel } from '../../model'
|
|
7
8
|
|
|
8
9
|
// icons
|
|
9
10
|
import Help from '@mui/icons-material/Help'
|
|
@@ -18,10 +19,14 @@ import HeaderMenuExtra from './HeaderMenuExtra'
|
|
|
18
19
|
const AboutDialog = lazy(() => import('../dialogs/AboutDialog'))
|
|
19
20
|
|
|
20
21
|
const Header = observer(function ({ model }: { model: MsaViewModel }) {
|
|
22
|
+
const [ref, { height }] = useMeasure()
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
model.setHeaderHeight(height || 0)
|
|
25
|
+
}, [model, height])
|
|
21
26
|
return (
|
|
22
|
-
<div style={{ display: 'flex' }}>
|
|
23
|
-
<ZoomControls model={model} />
|
|
27
|
+
<div ref={ref} style={{ display: 'flex' }}>
|
|
24
28
|
<HeaderMenuExtra model={model} />
|
|
29
|
+
<ZoomControls model={model} />
|
|
25
30
|
<MultiAlignmentSelector model={model} />
|
|
26
31
|
<HeaderInfoArea model={model} />
|
|
27
32
|
<Spacer />
|
|
@@ -10,7 +10,7 @@ import List from '@mui/icons-material/List'
|
|
|
10
10
|
import Menu from '@mui/icons-material/Menu'
|
|
11
11
|
|
|
12
12
|
// locals
|
|
13
|
-
import { MsaViewModel } from '../../model'
|
|
13
|
+
import type { MsaViewModel } from '../../model'
|
|
14
14
|
|
|
15
15
|
// lazies
|
|
16
16
|
const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
|
|
@@ -2,23 +2,20 @@ import React, { lazy } from 'react'
|
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
3
|
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
|
|
4
4
|
|
|
5
|
-
// locals
|
|
6
|
-
|
|
7
5
|
// icons
|
|
8
|
-
import MoreVert from '@mui/icons-material/
|
|
6
|
+
import MoreVert from '@mui/icons-material/Menu'
|
|
9
7
|
import Sort from '@mui/icons-material/Sort'
|
|
10
8
|
import Visibility from '@mui/icons-material/Visibility'
|
|
11
9
|
import FilterAlt from '@mui/icons-material/FilterAlt'
|
|
12
10
|
import Search from '@mui/icons-material/Search'
|
|
13
11
|
import PhotoCamera from '@mui/icons-material/PhotoCamera'
|
|
14
|
-
import RestartAlt from '@mui/icons-material/RestartAlt'
|
|
15
|
-
import FolderOpen from '@mui/icons-material/FolderOpen'
|
|
16
12
|
import Settings from '@mui/icons-material/Settings'
|
|
17
13
|
import Assignment from '@mui/icons-material/Assignment'
|
|
18
14
|
import List from '@mui/icons-material/List'
|
|
15
|
+
import FolderOpen from '@mui/icons-material/FolderOpen'
|
|
19
16
|
|
|
20
17
|
// locals
|
|
21
|
-
import { MsaViewModel } from '../../model'
|
|
18
|
+
import type { MsaViewModel } from '../../model'
|
|
22
19
|
|
|
23
20
|
// lazies
|
|
24
21
|
const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
|
|
@@ -26,10 +23,13 @@ const MetadataDialog = lazy(() => import('../dialogs/MetadataDialog'))
|
|
|
26
23
|
const TracklistDialog = lazy(() => import('../dialogs/TracklistDialog'))
|
|
27
24
|
const ExportSVGDialog = lazy(() => import('../dialogs/ExportSVGDialog'))
|
|
28
25
|
const FeatureFilterDialog = lazy(() => import('../dialogs/FeatureDialog'))
|
|
29
|
-
const
|
|
26
|
+
const UserProvidedDomainsDialog = lazy(
|
|
27
|
+
() => import('../dialogs/UserProvidedDomainsDialog'),
|
|
28
|
+
)
|
|
29
|
+
const InterProScanDialog = lazy(() => import('../dialogs/InterProScanDialog'))
|
|
30
30
|
|
|
31
|
-
const HeaderMenuExtra = observer(
|
|
32
|
-
const { showDomains, subFeatureRows,
|
|
31
|
+
const HeaderMenuExtra = observer(({ model }: { model: MsaViewModel }) => {
|
|
32
|
+
const { showDomains, actuallyShowDomains, subFeatureRows, noDomains } = model
|
|
33
33
|
return (
|
|
34
34
|
<CascadingMenuButton
|
|
35
35
|
menuItems={[
|
|
@@ -56,14 +56,7 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
56
56
|
model.queueDialog(onClose => [TracklistDialog, { model, onClose }]),
|
|
57
57
|
icon: List,
|
|
58
58
|
},
|
|
59
|
-
|
|
60
|
-
label: 'Reset zoom to default',
|
|
61
|
-
icon: RestartAlt,
|
|
62
|
-
onClick: () => {
|
|
63
|
-
model.setColWidth(16)
|
|
64
|
-
model.setRowHeight(20)
|
|
65
|
-
},
|
|
66
|
-
},
|
|
59
|
+
|
|
67
60
|
{
|
|
68
61
|
label: 'Export SVG',
|
|
69
62
|
icon: PhotoCamera,
|
|
@@ -75,23 +68,43 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
75
68
|
type: 'subMenu',
|
|
76
69
|
subMenu: [
|
|
77
70
|
{
|
|
78
|
-
label:
|
|
79
|
-
|
|
71
|
+
label: 'Open domains...',
|
|
72
|
+
icon: FolderOpen,
|
|
73
|
+
onClick: () =>
|
|
74
|
+
model.queueDialog(handleClose => [
|
|
75
|
+
UserProvidedDomainsDialog,
|
|
76
|
+
{ handleClose, model },
|
|
77
|
+
]),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Query InterProScan for domains...',
|
|
81
|
+
icon: Search,
|
|
82
|
+
onClick: () =>
|
|
83
|
+
model.queueDialog(handleClose => [
|
|
84
|
+
InterProScanDialog,
|
|
85
|
+
{ handleClose, model },
|
|
86
|
+
]),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: `Show domains${noDomains ? ' (no domains loaded)' : ''}`,
|
|
90
|
+
disabled: noDomains,
|
|
80
91
|
icon: Visibility,
|
|
81
|
-
checked: showDomains,
|
|
92
|
+
checked: actuallyShowDomains ? showDomains : false,
|
|
82
93
|
type: 'checkbox',
|
|
83
94
|
onClick: () => model.setShowDomains(!showDomains),
|
|
84
95
|
},
|
|
85
96
|
{
|
|
86
|
-
label:
|
|
87
|
-
|
|
97
|
+
label: `Use sub-row layout${noDomains ? ' (no domains loaded)' : ''}`,
|
|
98
|
+
disabled: noDomains,
|
|
99
|
+
checked: actuallyShowDomains ? subFeatureRows : false,
|
|
88
100
|
icon: Sort,
|
|
89
101
|
type: 'checkbox',
|
|
90
102
|
onClick: () => model.setSubFeatureRows(!subFeatureRows),
|
|
91
103
|
},
|
|
92
104
|
{
|
|
93
|
-
label:
|
|
105
|
+
label: `Filter domains${noDomains ? ' (no domains loaded)' : ''}`,
|
|
94
106
|
icon: FilterAlt,
|
|
107
|
+
disabled: noDomains,
|
|
95
108
|
onClick: () => {
|
|
96
109
|
model.queueDialog(onClose => [
|
|
97
110
|
FeatureFilterDialog,
|
|
@@ -99,15 +112,6 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
99
112
|
])
|
|
100
113
|
},
|
|
101
114
|
},
|
|
102
|
-
{
|
|
103
|
-
label: 'View domains',
|
|
104
|
-
icon: Search,
|
|
105
|
-
onClick: () =>
|
|
106
|
-
model.queueDialog(handleClose => [
|
|
107
|
-
DomainDialog,
|
|
108
|
-
{ handleClose, model },
|
|
109
|
-
]),
|
|
110
|
-
},
|
|
111
115
|
],
|
|
112
116
|
},
|
|
113
117
|
...(model.extraViewMenuItems?.() || []),
|
|
@@ -5,7 +5,7 @@ import { makeStyles } from 'tss-react/mui'
|
|
|
5
5
|
import { LoadingEllipses } from '@jbrowse/core/ui'
|
|
6
6
|
|
|
7
7
|
// locals
|
|
8
|
-
import { MsaViewModel } from '../../model'
|
|
8
|
+
import type { MsaViewModel } from '../../model'
|
|
9
9
|
|
|
10
10
|
const useStyles = makeStyles()({
|
|
11
11
|
margin: {
|
|
@@ -14,11 +14,7 @@ const useStyles = makeStyles()({
|
|
|
14
14
|
},
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
const HeaderStatusArea = observer(
|
|
18
|
-
model,
|
|
19
|
-
}: {
|
|
20
|
-
model: MsaViewModel
|
|
21
|
-
}) {
|
|
17
|
+
const HeaderStatusArea = observer(({ model }: { model: MsaViewModel }) => {
|
|
22
18
|
const { status } = model
|
|
23
19
|
const { classes } = useStyles()
|
|
24
20
|
return status ? (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { IconButton } from '@mui/material'
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
|
+
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
|
|
4
5
|
|
|
5
6
|
// locals
|
|
6
7
|
import { MsaViewModel } from '../../model'
|
|
@@ -8,6 +9,8 @@ import { MsaViewModel } from '../../model'
|
|
|
8
9
|
// icons
|
|
9
10
|
import ZoomIn from '@mui/icons-material/ZoomIn'
|
|
10
11
|
import ZoomOut from '@mui/icons-material/ZoomOut'
|
|
12
|
+
import MoreVert from '@mui/icons-material/MoreVert'
|
|
13
|
+
import RestartAlt from '@mui/icons-material/RestartAlt'
|
|
11
14
|
|
|
12
15
|
const ZoomControls = observer(function ZoomControls({
|
|
13
16
|
model,
|
|
@@ -22,6 +25,37 @@ const ZoomControls = observer(function ZoomControls({
|
|
|
22
25
|
<IconButton onClick={() => model.zoomOut()}>
|
|
23
26
|
<ZoomOut />
|
|
24
27
|
</IconButton>
|
|
28
|
+
<CascadingMenuButton
|
|
29
|
+
menuItems={[
|
|
30
|
+
{
|
|
31
|
+
label: 'Zoom in horizontal',
|
|
32
|
+
onClick: () => model.zoomInHorizontal(),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: 'Zoom in vertical',
|
|
36
|
+
onClick: () => model.zoomInVertical(),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
label: 'Zoom out horizontal',
|
|
40
|
+
onClick: () => model.zoomOutHorizontal(),
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
label: 'Zoom out vertical',
|
|
45
|
+
onClick: () => model.zoomOutVertical(),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: 'Reset zoom to default',
|
|
49
|
+
icon: RestartAlt,
|
|
50
|
+
onClick: () => {
|
|
51
|
+
model.setColWidth(16)
|
|
52
|
+
model.setRowHeight(20)
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
]}
|
|
56
|
+
>
|
|
57
|
+
<MoreVert />
|
|
58
|
+
</CascadingMenuButton>
|
|
25
59
|
</>
|
|
26
60
|
)
|
|
27
61
|
})
|
|
@@ -2,14 +2,14 @@ import React, { useState } from 'react'
|
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
3
|
import { Button, Container, Grid, Typography } from '@mui/material'
|
|
4
4
|
import { FileSelector } from '@jbrowse/core/ui'
|
|
5
|
-
import { FileLocation } from '@jbrowse/core/util/types'
|
|
5
|
+
import type { FileLocation } from '@jbrowse/core/util/types'
|
|
6
6
|
|
|
7
7
|
// locals
|
|
8
|
-
import { MsaViewModel } from '../../model'
|
|
8
|
+
import type { MsaViewModel } from '../../model'
|
|
9
9
|
import { load } from './util'
|
|
10
10
|
import ImportFormExamples from './ImportFormExamples'
|
|
11
11
|
|
|
12
|
-
export default observer(({ model }: { model: MsaViewModel })
|
|
12
|
+
export default observer(function ({ model }: { model: MsaViewModel }) {
|
|
13
13
|
const [msaFile, setMsaFile] = useState<FileLocation>()
|
|
14
14
|
const [treeFile, setTreeFile] = useState<FileLocation>()
|
|
15
15
|
const { error } = model
|
|
@@ -3,11 +3,11 @@ import { Typography, Link } from '@mui/material'
|
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
4
|
|
|
5
5
|
// locals
|
|
6
|
-
import { MsaViewModel } from '../../model'
|
|
6
|
+
import type { MsaViewModel } from '../../model'
|
|
7
7
|
import { smallTree, smallMSA, smallMSAOnly } from './data/seq2'
|
|
8
8
|
import { load } from './util'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
function ListItem({
|
|
11
11
|
onClick,
|
|
12
12
|
model,
|
|
13
13
|
children,
|
|
@@ -15,20 +15,22 @@ const ListItem = ({
|
|
|
15
15
|
onClick: () => void
|
|
16
16
|
model: MsaViewModel
|
|
17
17
|
children: React.ReactNode
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
}) {
|
|
19
|
+
return (
|
|
20
|
+
<li>
|
|
21
|
+
<Link
|
|
22
|
+
onClick={event => {
|
|
23
|
+
model.setError(undefined)
|
|
24
|
+
event.preventDefault()
|
|
25
|
+
onClick()
|
|
26
|
+
}}
|
|
27
|
+
href="#"
|
|
28
|
+
>
|
|
29
|
+
<Typography display="inline">{children}</Typography>
|
|
30
|
+
</Link>
|
|
31
|
+
</li>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
32
34
|
|
|
33
35
|
const ImportFormExamples = observer(function ({
|
|
34
36
|
model,
|
|
@@ -41,7 +43,7 @@ const ImportFormExamples = observer(function ({
|
|
|
41
43
|
model={model}
|
|
42
44
|
onClick={() =>
|
|
43
45
|
load(model, undefined, {
|
|
44
|
-
uri: 'https://jbrowse.org/genomes/
|
|
46
|
+
uri: 'https://jbrowse.org/genomes/newicktrees/sarscov2phylo.pub.ft.nh',
|
|
45
47
|
locationType: 'UriLocation',
|
|
46
48
|
})
|
|
47
49
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
|
-
import { MsaViewModel } from '../../model'
|
|
3
|
+
import type { MsaViewModel } from '../../model'
|
|
4
4
|
|
|
5
5
|
const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
|
|
6
6
|
const [mouseDown, setMouseDown] = useState<{
|
|
@@ -9,19 +9,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
9
9
|
}>()
|
|
10
10
|
const scheduled = useRef(false)
|
|
11
11
|
const [hovered, setHovered] = useState(false)
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
msaAreaWidth: W,
|
|
15
|
-
minimapHeight: H,
|
|
16
|
-
colWidth,
|
|
17
|
-
numColumns,
|
|
18
|
-
} = model
|
|
19
|
-
const unit = W / numColumns / colWidth
|
|
12
|
+
const { scrollX, msaAreaWidth, minimapHeight, colWidth, numColumns } = model
|
|
13
|
+
const unit = msaAreaWidth / numColumns / colWidth
|
|
20
14
|
const left = -scrollX
|
|
21
|
-
const right = left +
|
|
15
|
+
const right = left + msaAreaWidth
|
|
22
16
|
const s = left * unit
|
|
23
17
|
const e = right * unit
|
|
24
18
|
const fill = 'rgba(66, 119, 127, 0.3)'
|
|
19
|
+
const w = Math.max(e - s, 20)
|
|
25
20
|
|
|
26
21
|
useEffect(() => {
|
|
27
22
|
function fn(event: MouseEvent) {
|
|
@@ -50,14 +45,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
50
45
|
}
|
|
51
46
|
}, [model, unit, mouseDown])
|
|
52
47
|
|
|
53
|
-
const
|
|
54
|
-
const
|
|
48
|
+
const barHeight = 12
|
|
49
|
+
const polygonHeight = minimapHeight - barHeight
|
|
55
50
|
return (
|
|
56
|
-
<div style={{ position: 'relative', height:
|
|
51
|
+
<div style={{ position: 'relative', height: minimapHeight, width: '100%' }}>
|
|
57
52
|
<div
|
|
58
53
|
style={{
|
|
59
54
|
boxSizing: 'border-box',
|
|
60
|
-
height:
|
|
55
|
+
height: barHeight,
|
|
61
56
|
border: '1px solid #555',
|
|
62
57
|
}}
|
|
63
58
|
/>
|
|
@@ -68,10 +63,8 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
68
63
|
left: Math.max(0, s),
|
|
69
64
|
background: hovered ? 'rgba(66,119,127,0.6)' : fill,
|
|
70
65
|
cursor: 'pointer',
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
height: BAR_HEIGHT,
|
|
74
|
-
width: e - s,
|
|
66
|
+
height: barHeight,
|
|
67
|
+
width: w,
|
|
75
68
|
zIndex: 100,
|
|
76
69
|
}}
|
|
77
70
|
onMouseOver={() => setHovered(true)}
|
|
@@ -84,14 +77,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
84
77
|
}}
|
|
85
78
|
/>
|
|
86
79
|
|
|
87
|
-
<svg height={
|
|
80
|
+
<svg height={polygonHeight} style={{ width: '100%' }}>
|
|
88
81
|
<polygon
|
|
89
82
|
fill={fill}
|
|
90
83
|
points={[
|
|
91
|
-
[
|
|
84
|
+
[s + w, 0],
|
|
92
85
|
[s, 0],
|
|
93
|
-
[0,
|
|
94
|
-
[
|
|
86
|
+
[0, polygonHeight],
|
|
87
|
+
[msaAreaWidth, polygonHeight],
|
|
95
88
|
].toString()}
|
|
96
89
|
/>
|
|
97
90
|
</svg>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
|
-
import { MsaViewModel } from '../../model'
|
|
3
|
+
import type { MsaViewModel } from '../../model'
|
|
4
4
|
|
|
5
|
-
const MinimapSVG = observer(
|
|
5
|
+
const MinimapSVG = observer(({ model }: { model: MsaViewModel }) => {
|
|
6
6
|
const {
|
|
7
7
|
scrollX,
|
|
8
8
|
msaAreaWidth: W,
|