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