react-msaview 8.0.0 → 8.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 +99 -99
- package/bundle/index.js.map +3 -3
- package/dist/calculateBlocks.js +5 -3
- package/dist/calculateBlocks.js.map +1 -1
- package/dist/components/Loading.js +2 -8
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/SequenceTextArea.js +0 -1
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/Track.js +2 -2
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/AboutDialog.js +6 -6
- package/dist/components/dialogs/AboutDialog.js.map +1 -1
- package/dist/components/dialogs/AnnotationFileDialog.js +5 -2
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +1 -1
- package/dist/components/dialogs/FeatureDialog.js +8 -3
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/header/Header.js +1 -1
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/LoadWarnings.js +3 -19
- package/dist/components/header/LoadWarnings.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +3 -3
- 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/msa/MSACanvas.js +1 -3
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/drawFeatureSpans.d.ts +7 -1
- package/dist/components/msa/drawFeatureSpans.js +58 -23
- package/dist/components/msa/drawFeatureSpans.js.map +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +7 -8
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +8 -9
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/tracks/drawTracks.js +8 -5
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tree/TreeBranchMenu.js +1 -1
- package/dist/components/tree/TreeBranchMenu.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +1 -3
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -2
- 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/renderTreeCanvas.js +2 -1
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +4 -0
- package/dist/constants.js.map +1 -1
- package/dist/expandSpec.d.ts +46 -0
- package/dist/expandSpec.js +127 -0
- package/dist/expandSpec.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +52 -33
- package/dist/model.js +232 -142
- package/dist/model.js.map +1 -1
- package/dist/svgTestUtil.d.ts +28 -24
- package/dist/types.d.ts +2 -0
- package/dist/useWheelScroll.js +0 -4
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/calculateBlocks.ts +5 -3
- package/src/components/Loading.tsx +2 -30
- package/src/components/SequenceTextArea.tsx +0 -1
- package/src/components/Track.tsx +2 -1
- package/src/components/dialogs/AboutDialog.tsx +35 -6
- package/src/components/dialogs/AnnotationFileDialog.tsx +10 -1
- package/src/components/dialogs/ExportSVGDialog.tsx +1 -1
- package/src/components/dialogs/FeatureDialog.tsx +11 -3
- package/src/components/header/Header.tsx +1 -1
- package/src/components/header/LoadWarnings.tsx +8 -21
- package/src/components/header/settingsMenuItems.ts +3 -3
- package/src/components/import/ImportForm.tsx +3 -5
- package/src/components/msa/MSACanvas.tsx +0 -3
- package/src/components/msa/drawFeatureSpans.ts +80 -25
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +7 -9
- package/src/components/msa/renderMSABlock.ts +9 -8
- package/src/components/tracks/drawTracks.ts +8 -16
- package/src/components/tree/TreeBranchMenu.tsx +1 -2
- package/src/components/tree/TreeCanvas.tsx +0 -3
- package/src/components/tree/TreeCanvasBlock.tsx +2 -2
- package/src/components/tree/TreeNodeMenu.tsx +1 -2
- package/src/components/tree/renderTreeCanvas.ts +2 -1
- package/src/constants.ts +5 -0
- package/src/expandSpec.ts +196 -0
- package/src/index.ts +8 -0
- package/src/model.ts +289 -162
- package/src/types.ts +2 -0
- package/src/useWheelScroll.ts +0 -4
- package/src/version.ts +1 -1
package/dist/useWheelScroll.js
CHANGED
|
@@ -116,10 +116,6 @@ export function useWheelScroll({ ref, onScrollX, onScrollY, onZoom, scrollZoom,
|
|
|
116
116
|
};
|
|
117
117
|
}, [mouseDragging, onScrollX, onScrollY]);
|
|
118
118
|
function onMouseDown(event) {
|
|
119
|
-
const target = event.target;
|
|
120
|
-
if (target.draggable || target.dataset.resizer) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
119
|
if (event.button === 0) {
|
|
124
120
|
prevX.current = event.clientX;
|
|
125
121
|
prevY.current = event.clientY;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWheelScroll.js","sourceRoot":"","sources":["../src/useWheelScroll.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"useWheelScroll.js","sourceRoot":"","sources":["../src/useWheelScroll.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "8.
|
|
1
|
+
export declare const version = "8.2.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '8.
|
|
1
|
+
export const version = '8.2.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-msaview",
|
|
3
3
|
"author": "Colin",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.2.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@gmod/newick": "^1.0.3",
|
|
53
|
-
"@jbrowse/svgcanvas": "8.
|
|
53
|
+
"@jbrowse/svgcanvas": "8.2.0",
|
|
54
54
|
"colord": "^2.10.0",
|
|
55
55
|
"flatbush": "^4.6.2",
|
|
56
|
-
"msa-parsers": "8.
|
|
56
|
+
"msa-parsers": "8.2.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"clean": "rimraf dist bundle",
|
package/src/calculateBlocks.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Returns the block offsets (in pixels) needed to cover the viewport along one
|
|
2
2
|
// axis. mapSize/viewportPos/viewportSize are all in pixels. The clamp pins the
|
|
3
|
-
// block set to the content edge so an over-scroll past the end still fills
|
|
4
|
-
// viewport
|
|
3
|
+
// block set to the content edge, so an over-scroll past the end still fills
|
|
4
|
+
// the viewport, and content smaller than the viewport mounts only the blocks
|
|
5
|
+
// it covers: none for a tree-only figure with zero columns.
|
|
5
6
|
export function calculateBlocks({
|
|
6
7
|
mapSize,
|
|
7
8
|
blockSize,
|
|
@@ -14,8 +15,9 @@ export function calculateBlocks({
|
|
|
14
15
|
viewportSize: number
|
|
15
16
|
}) {
|
|
16
17
|
const clamped = Math.max(0, Math.min(viewportPos, mapSize - viewportSize))
|
|
18
|
+
const end = Math.min(clamped + viewportSize, mapSize)
|
|
17
19
|
const minTile = Math.floor(clamped / blockSize)
|
|
18
|
-
const maxTile = Math.
|
|
20
|
+
const maxTile = Math.ceil(end / blockSize) - 1
|
|
19
21
|
|
|
20
22
|
const blocks = []
|
|
21
23
|
for (let tile = minTile; tile <= maxTile; tile++) {
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { ErrorMessage } from '@jbrowse/core/ui'
|
|
4
4
|
import { ErrorBoundary } from '@jbrowse/core/ui/ErrorBoundary'
|
|
5
|
-
import { Button, Typography } from '@mui/material'
|
|
5
|
+
import { Button, CircularProgress, Typography } from '@mui/material'
|
|
6
6
|
import { observer } from 'mobx-react'
|
|
7
7
|
|
|
8
8
|
import MSAView from './MSAView.tsx'
|
|
@@ -16,35 +16,7 @@ const LoadingSpinner = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
16
16
|
<div
|
|
17
17
|
style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 20 }}
|
|
18
18
|
>
|
|
19
|
-
<
|
|
20
|
-
width="24"
|
|
21
|
-
height="24"
|
|
22
|
-
viewBox="0 0 24 24"
|
|
23
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
-
>
|
|
25
|
-
<style>
|
|
26
|
-
{`@keyframes spinner { to { transform: rotate(360deg); } }`}
|
|
27
|
-
</style>
|
|
28
|
-
<circle
|
|
29
|
-
cx="12"
|
|
30
|
-
cy="12"
|
|
31
|
-
r="10"
|
|
32
|
-
stroke="#ccc"
|
|
33
|
-
strokeWidth="3"
|
|
34
|
-
fill="none"
|
|
35
|
-
/>
|
|
36
|
-
<path
|
|
37
|
-
d="M12 2a10 10 0 0 1 10 10"
|
|
38
|
-
stroke="#1976d2"
|
|
39
|
-
strokeWidth="3"
|
|
40
|
-
fill="none"
|
|
41
|
-
strokeLinecap="round"
|
|
42
|
-
style={{
|
|
43
|
-
animation: 'spinner 1s linear infinite',
|
|
44
|
-
transformOrigin: 'center',
|
|
45
|
-
}}
|
|
46
|
-
/>
|
|
47
|
-
</svg>
|
|
19
|
+
<CircularProgress size={24} />
|
|
48
20
|
<Typography variant="h6">{status?.msg ?? 'Loading...'}</Typography>
|
|
49
21
|
{status?.onCancel ? (
|
|
50
22
|
<Button
|
package/src/components/Track.tsx
CHANGED
|
@@ -78,6 +78,7 @@ const TrackLabel = observer(function TrackLabel({
|
|
|
78
78
|
</span>
|
|
79
79
|
<IconButton
|
|
80
80
|
className={classes.button}
|
|
81
|
+
aria-label={`${name} track menu`}
|
|
81
82
|
style={{
|
|
82
83
|
width: trackLabelHeight,
|
|
83
84
|
height: trackLabelHeight,
|
|
@@ -105,7 +106,7 @@ const TrackLabel = observer(function TrackLabel({
|
|
|
105
106
|
closeMenu()
|
|
106
107
|
}}
|
|
107
108
|
>
|
|
108
|
-
|
|
109
|
+
Hide track
|
|
109
110
|
</MenuItem>
|
|
110
111
|
<MenuItem
|
|
111
112
|
dense
|
|
@@ -17,16 +17,33 @@ export default function AboutDialog({ onClose }: { onClose: () => void }) {
|
|
|
17
17
|
<DialogContent>
|
|
18
18
|
<Typography>
|
|
19
19
|
MSAView {version} (
|
|
20
|
-
<Link
|
|
20
|
+
<Link
|
|
21
|
+
target="_blank"
|
|
22
|
+
rel="noopener"
|
|
23
|
+
href="https://github.com/gmod/react-msaview"
|
|
24
|
+
>
|
|
25
|
+
Github
|
|
26
|
+
</Link>
|
|
27
|
+
)
|
|
21
28
|
</Typography>
|
|
22
29
|
|
|
23
30
|
<ul>
|
|
24
31
|
<li>
|
|
25
32
|
<Typography>
|
|
26
33
|
We use some color schemes from the{' '}
|
|
27
|
-
<Link
|
|
34
|
+
<Link
|
|
35
|
+
target="_blank"
|
|
36
|
+
rel="noopener"
|
|
37
|
+
href="https://github.com/biotite-dev/biotite"
|
|
38
|
+
>
|
|
39
|
+
biotite
|
|
40
|
+
</Link>{' '}
|
|
28
41
|
project, and their license is reproduced{' '}
|
|
29
|
-
<Link
|
|
42
|
+
<Link
|
|
43
|
+
target="_blank"
|
|
44
|
+
rel="noopener"
|
|
45
|
+
href="https://github.com/biotite-dev/biotite/blob/master/LICENSE.rst"
|
|
46
|
+
>
|
|
30
47
|
here
|
|
31
48
|
</Link>
|
|
32
49
|
</Typography>
|
|
@@ -34,7 +51,11 @@ export default function AboutDialog({ onClose }: { onClose: () => void }) {
|
|
|
34
51
|
<li>
|
|
35
52
|
<Typography>
|
|
36
53
|
See this page for some information on jalview colorings{' '}
|
|
37
|
-
<Link
|
|
54
|
+
<Link
|
|
55
|
+
target="_blank"
|
|
56
|
+
rel="noopener"
|
|
57
|
+
href="https://www.jalview.org/help/html/colourSchemes/"
|
|
58
|
+
>
|
|
38
59
|
here
|
|
39
60
|
</Link>
|
|
40
61
|
</Typography>
|
|
@@ -43,7 +64,11 @@ export default function AboutDialog({ onClose }: { onClose: () => void }) {
|
|
|
43
64
|
<Typography>
|
|
44
65
|
See this page for some info on the clustal, cinema, maeditor, and
|
|
45
66
|
lesk color schemes{' '}
|
|
46
|
-
<Link
|
|
67
|
+
<Link
|
|
68
|
+
target="_blank"
|
|
69
|
+
rel="noopener"
|
|
70
|
+
href="http://www.bioinformatics.nl/~berndb/aacolour.html"
|
|
71
|
+
>
|
|
47
72
|
here
|
|
48
73
|
</Link>
|
|
49
74
|
</Typography>
|
|
@@ -51,7 +76,11 @@ export default function AboutDialog({ onClose }: { onClose: () => void }) {
|
|
|
51
76
|
<li>
|
|
52
77
|
<Typography>
|
|
53
78
|
See this paper about the flower color scheme{' '}
|
|
54
|
-
<Link
|
|
79
|
+
<Link
|
|
80
|
+
target="_blank"
|
|
81
|
+
rel="noopener"
|
|
82
|
+
href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7245768/"
|
|
83
|
+
>
|
|
55
84
|
here
|
|
56
85
|
</Link>
|
|
57
86
|
</Typography>
|
|
@@ -126,7 +126,7 @@ const AnnotationFileDialog = observer(function ({
|
|
|
126
126
|
<Button
|
|
127
127
|
variant="contained"
|
|
128
128
|
color="primary"
|
|
129
|
-
disabled={loading}
|
|
129
|
+
disabled={loading || (choice === 'file' ? !file : !url.trim())}
|
|
130
130
|
onClick={() => {
|
|
131
131
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
132
132
|
;(async () => {
|
|
@@ -154,6 +154,15 @@ const AnnotationFileDialog = observer(function ({
|
|
|
154
154
|
>
|
|
155
155
|
Open annotations
|
|
156
156
|
</Button>
|
|
157
|
+
<Button
|
|
158
|
+
variant="contained"
|
|
159
|
+
color="secondary"
|
|
160
|
+
onClick={() => {
|
|
161
|
+
handleClose()
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
Cancel
|
|
165
|
+
</Button>
|
|
157
166
|
</DialogActions>
|
|
158
167
|
</Dialog>
|
|
159
168
|
)
|
|
@@ -47,10 +47,18 @@ const Toggles = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
const FeatureTable = observer(function ({ model }: { model: MsaViewModel }) {
|
|
50
|
-
const { annotationTypes, annotations, fillPalette } = model
|
|
50
|
+
const { annotationTypes, annotations, featureColors, fillPalette } = model
|
|
51
51
|
const counts = new Map<string, number>()
|
|
52
|
+
const swatches = new Map<string, string>()
|
|
52
53
|
for (const annot of annotations) {
|
|
53
|
-
|
|
54
|
+
const { accession } = annot
|
|
55
|
+
counts.set(accession, (counts.get(accession) ?? 0) + 1)
|
|
56
|
+
if (!swatches.has(accession)) {
|
|
57
|
+
swatches.set(
|
|
58
|
+
accession,
|
|
59
|
+
featureColors.get(annot)?.fill ?? fillPalette[accession]!,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
return (
|
|
56
64
|
<>
|
|
@@ -86,7 +94,7 @@ const FeatureTable = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
86
94
|
style={{
|
|
87
95
|
width: 20,
|
|
88
96
|
height: 20,
|
|
89
|
-
background:
|
|
97
|
+
background: swatches.get(accession),
|
|
90
98
|
}}
|
|
91
99
|
/>
|
|
92
100
|
</TableCell>
|
|
@@ -34,7 +34,7 @@ const Header = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
34
34
|
[model],
|
|
35
35
|
)
|
|
36
36
|
return (
|
|
37
|
-
<div ref={ref} style={{ display: 'flex' }}>
|
|
37
|
+
<div ref={ref} style={{ display: 'flex', flexWrap: 'wrap' }}>
|
|
38
38
|
<FileMenu model={model} />
|
|
39
39
|
<ColorSchemeMenu model={model} />
|
|
40
40
|
<TreeSettingsMenu model={model} />
|
|
@@ -1,46 +1,33 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react'
|
|
4
3
|
import Warning from '@mui/icons-material/Warning'
|
|
5
|
-
import {
|
|
4
|
+
import { Button, Tooltip } from '@mui/material'
|
|
6
5
|
import { observer } from 'mobx-react'
|
|
7
6
|
|
|
8
7
|
import type { MsaViewModel } from '../../model.ts'
|
|
9
8
|
|
|
10
|
-
const useStyles = makeStyles()(theme => ({
|
|
11
|
-
warning: {
|
|
12
|
-
display: 'flex',
|
|
13
|
-
alignItems: 'center',
|
|
14
|
-
gap: 4,
|
|
15
|
-
margin: 'auto',
|
|
16
|
-
marginLeft: 10,
|
|
17
|
-
whiteSpace: 'nowrap',
|
|
18
|
-
color: theme.palette.warning.main,
|
|
19
|
-
cursor: 'pointer',
|
|
20
|
-
},
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
9
|
// A failed optional layer, such as a 404 on the annotations or row metadata
|
|
24
10
|
// that is not JSON, shows here as a dismissible warning. Setting `error` would
|
|
25
11
|
// clear dataInitialized and hide the loaded alignment.
|
|
26
12
|
const LoadWarnings = observer(function ({ model }: { model: MsaViewModel }) {
|
|
27
13
|
const { warnings } = model
|
|
28
|
-
const { classes } = useStyles()
|
|
29
14
|
if (warnings.length === 0) {
|
|
30
15
|
return null
|
|
31
16
|
}
|
|
32
17
|
return (
|
|
33
18
|
<Tooltip title={`${warnings.join(' ')} (click to dismiss)`}>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
<Button
|
|
20
|
+
aria-label="Dismiss warnings"
|
|
21
|
+
color="warning"
|
|
22
|
+
size="small"
|
|
23
|
+
startIcon={<Warning fontSize="small" />}
|
|
24
|
+
style={{ margin: 'auto', marginLeft: 10, whiteSpace: 'nowrap' }}
|
|
37
25
|
onClick={() => {
|
|
38
26
|
model.clearWarnings()
|
|
39
27
|
}}
|
|
40
28
|
>
|
|
41
|
-
<Warning fontSize="small" />
|
|
42
29
|
{warnings.length > 1 ? `${warnings.length} warnings` : 'Warning'}
|
|
43
|
-
</
|
|
30
|
+
</Button>
|
|
44
31
|
</Tooltip>
|
|
45
32
|
)
|
|
46
33
|
})
|
|
@@ -12,7 +12,7 @@ function toggle(label: string, checked: boolean, set: (arg: boolean) => void) {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
// the only place in the UI to turn a
|
|
15
|
+
// the only place in the UI to turn a hidden track back on
|
|
16
16
|
function tracksSubMenu(model: MsaViewModel): MenuItem[] {
|
|
17
17
|
const shown = new Set(model.turnedOnTracks.map(t => t.model.id))
|
|
18
18
|
return model.tracks.map(({ model: { id, name } }) =>
|
|
@@ -38,10 +38,10 @@ export function msaSettingsMenuItems(model: MsaViewModel): MenuItem[] {
|
|
|
38
38
|
model.setDrawMsaLetters(arg)
|
|
39
39
|
}),
|
|
40
40
|
// inverted: bgColor colors the tile, and off colors the letter
|
|
41
|
-
toggle('Color letters
|
|
41
|
+
toggle('Color letters, not cells', !bgColor, arg => {
|
|
42
42
|
model.setBgColor(!arg)
|
|
43
43
|
}),
|
|
44
|
-
toggle('
|
|
44
|
+
toggle('Hide gappy columns', hideGaps, arg => {
|
|
45
45
|
model.setHideGaps(arg)
|
|
46
46
|
}),
|
|
47
47
|
]
|
|
@@ -24,11 +24,9 @@ const ImportForm = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
24
24
|
Open an MSA file (FASTA, Stockholm, Clustal, A3M or EMF format) and/or
|
|
25
25
|
a tree file (Newick format).
|
|
26
26
|
</Typography>
|
|
27
|
-
<Typography color="
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
also and this is fine, and opening a separate tree file is not
|
|
31
|
-
required.
|
|
27
|
+
<Typography color="text.secondary">
|
|
28
|
+
An MSA alone or a tree alone is enough, and a Stockholm file with an
|
|
29
|
+
embedded tree needs no separate tree file.
|
|
32
30
|
</Typography>
|
|
33
31
|
</div>
|
|
34
32
|
|
|
@@ -54,9 +54,6 @@ const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
54
54
|
data-testid="msa_canvas"
|
|
55
55
|
onMouseDown={onMouseDown}
|
|
56
56
|
onMouseUp={onMouseUp}
|
|
57
|
-
onMouseLeave={event => {
|
|
58
|
-
event.preventDefault()
|
|
59
|
-
}}
|
|
60
57
|
style={{
|
|
61
58
|
position: 'relative',
|
|
62
59
|
height,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { minFeatureLabelHeight } from '../../constants.ts'
|
|
2
|
+
|
|
1
3
|
import type { HierarchyNode } from '../../hierarchy.ts'
|
|
2
4
|
import type { Annotation, NodeWithIdsAndLength } from '../../types.ts'
|
|
3
5
|
import type { RenderCtx } from '../renderCtx.ts'
|
|
@@ -25,8 +27,14 @@ export interface SpanLayout {
|
|
|
25
27
|
height: (laneCount: number) => number
|
|
26
28
|
/** the band's top edge, from its row baseline, its lane and its height */
|
|
27
29
|
top: (y: number, lane: number, height: number) => number
|
|
28
|
-
/** how far
|
|
30
|
+
/** how far back from the feature's end the head starts */
|
|
29
31
|
headLength: (height: number) => number
|
|
32
|
+
/**
|
|
33
|
+
* how far the head rises above the band. A bar too thin to taper reads its
|
|
34
|
+
* direction off a head taller than itself, and the bar sits on the row's
|
|
35
|
+
* bottom edge, so the room is above.
|
|
36
|
+
*/
|
|
37
|
+
headRise?: (height: number) => number
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
/** the rows of `bandsByRow` that `leaves` covers, in display order */
|
|
@@ -76,9 +84,26 @@ export function drawFeatureSpans<T extends SpanBand>({
|
|
|
76
84
|
xMin: number
|
|
77
85
|
xMax: number
|
|
78
86
|
}) {
|
|
87
|
+
// one row's spans are drawn before any of its labels. Bands are ordered
|
|
88
|
+
// longest-first so a nested one lands on top, and drawing each label with its
|
|
89
|
+
// own span put the child's box over the parent's text: `S` covered `RBD`, and
|
|
90
|
+
// `RBD` read as `RB`. Reused across rows rather than allocated per row.
|
|
91
|
+
const placed: {
|
|
92
|
+
band: T
|
|
93
|
+
xStart: number
|
|
94
|
+
w: number
|
|
95
|
+
t: number
|
|
96
|
+
head: number
|
|
97
|
+
fill: string
|
|
98
|
+
}[] = []
|
|
99
|
+
|
|
79
100
|
for (const { y, bands } of rows) {
|
|
80
101
|
const h = layout.height(bands[0]!.laneCount)
|
|
81
102
|
const headLen = layout.headLength(h)
|
|
103
|
+
const rise = layout.headRise?.(h) ?? 0
|
|
104
|
+
const labelled = labelOf !== undefined && h >= minFeatureLabelHeight
|
|
105
|
+
placed.length = 0
|
|
106
|
+
|
|
82
107
|
for (const band of bands) {
|
|
83
108
|
const [xStart, xEnd] = xOf(band)
|
|
84
109
|
const w = xEnd - xStart
|
|
@@ -90,21 +115,33 @@ export function drawFeatureSpans<T extends SpanBand>({
|
|
|
90
115
|
ctx.fillStyle = fill
|
|
91
116
|
ctx.strokeStyle = stroke
|
|
92
117
|
const { strand } = band.annotation
|
|
118
|
+
const head = strand === undefined ? 0 : Math.min(headLen, w)
|
|
93
119
|
if (strand === undefined) {
|
|
94
120
|
ctx.fillRect(xStart, t, w, h)
|
|
95
121
|
ctx.strokeRect(xStart, t, w, h)
|
|
96
122
|
} else {
|
|
97
|
-
drawGeneArrow({ ctx, x: xStart, t, w, h,
|
|
123
|
+
drawGeneArrow({ ctx, x: xStart, t, w, h, head, rise, strand })
|
|
98
124
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
if (labelled) {
|
|
126
|
+
placed.push({ band, xStart, w, t, head, fill })
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (placed.length > 0) {
|
|
131
|
+
ctx.font = `${Math.min(h - 2, 11)}px sans-serif`
|
|
132
|
+
ctx.textAlign = 'center'
|
|
133
|
+
ctx.textBaseline = 'middle'
|
|
134
|
+
for (const { band, xStart, w, t, head, fill } of placed) {
|
|
135
|
+
// asking for the label here rather than in the pass above keeps the
|
|
136
|
+
// once-per-block segment numbering in drawing order
|
|
137
|
+
const label = labelOf!(band)
|
|
138
|
+
// the head narrows to a point, so only about half of it holds text
|
|
139
|
+
if (
|
|
140
|
+
label !== undefined &&
|
|
141
|
+
ctx.measureText(label).width + 2 <= w - head / 2
|
|
142
|
+
) {
|
|
104
143
|
labelDrawn?.(band)
|
|
105
144
|
ctx.fillStyle = contrastText(fill)
|
|
106
|
-
ctx.textAlign = 'center'
|
|
107
|
-
ctx.textBaseline = 'middle'
|
|
108
145
|
ctx.fillText(label, xStart + w / 2, t + h / 2)
|
|
109
146
|
}
|
|
110
147
|
}
|
|
@@ -112,19 +149,24 @@ export function drawFeatureSpans<T extends SpanBand>({
|
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
151
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
/**
|
|
153
|
+
* A gene arrow, drawn the way gggenes and gggenomes draw one: the head is the
|
|
154
|
+
* last `head` pixels *of* the feature, tapering to a point at its end, and a
|
|
155
|
+
* feature shorter than the head is all head. The glyph therefore covers its
|
|
156
|
+
* start..end span and nothing else, so adjacent genes butt together instead of
|
|
157
|
+
* biting triangles out of each other, a neighbour never draws over a label, and
|
|
158
|
+
* a gene 20 columns wide reads as 20 columns wide.
|
|
159
|
+
*
|
|
160
|
+
* `rise` lifts the head above the band, for a bar too thin to taper.
|
|
161
|
+
*/
|
|
121
162
|
function drawGeneArrow({
|
|
122
163
|
ctx,
|
|
123
164
|
x,
|
|
124
165
|
t,
|
|
125
166
|
w,
|
|
126
167
|
h,
|
|
127
|
-
|
|
168
|
+
head,
|
|
169
|
+
rise,
|
|
128
170
|
strand,
|
|
129
171
|
}: {
|
|
130
172
|
ctx: RenderCtx
|
|
@@ -132,18 +174,31 @@ function drawGeneArrow({
|
|
|
132
174
|
t: number
|
|
133
175
|
w: number
|
|
134
176
|
h: number
|
|
135
|
-
|
|
177
|
+
head: number
|
|
178
|
+
rise: number
|
|
136
179
|
strand: number
|
|
137
180
|
}) {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
181
|
+
const tip = strand > 0 ? x + w : x
|
|
182
|
+
const tail = strand > 0 ? x : x + w
|
|
183
|
+
const flange = strand > 0 ? tip - head : tip + head
|
|
184
|
+
const bottom = t + h
|
|
185
|
+
const crown = t - rise
|
|
186
|
+
const point = (crown + bottom) / 2
|
|
141
187
|
ctx.beginPath()
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
188
|
+
if (head >= w) {
|
|
189
|
+
ctx.moveTo(tail, crown)
|
|
190
|
+
ctx.lineTo(tip, point)
|
|
191
|
+
ctx.lineTo(tail, bottom)
|
|
192
|
+
} else {
|
|
193
|
+
ctx.moveTo(tail, t)
|
|
194
|
+
ctx.lineTo(flange, t)
|
|
195
|
+
if (rise > 0) {
|
|
196
|
+
ctx.lineTo(flange, crown)
|
|
197
|
+
}
|
|
198
|
+
ctx.lineTo(tip, point)
|
|
199
|
+
ctx.lineTo(flange, bottom)
|
|
200
|
+
ctx.lineTo(tail, bottom)
|
|
201
|
+
}
|
|
147
202
|
ctx.closePath()
|
|
148
203
|
ctx.fill()
|
|
149
204
|
ctx.stroke()
|
|
@@ -60,16 +60,12 @@ export function renderBoxFeatureCanvasBlock({
|
|
|
60
60
|
// out); when letters show, the alternating shades alone mark the boundaries
|
|
61
61
|
// and a number would collide with the sequence. A featureLabel encoding names
|
|
62
62
|
// what every span carries instead
|
|
63
|
-
const drawSegmentLabels =
|
|
64
|
-
!featureLabels && !showMsaLetters && !subFeatureRows && barHeight >= 9
|
|
63
|
+
const drawSegmentLabels = !featureLabels && !showMsaLetters && !subFeatureRows
|
|
65
64
|
// a segment (exon) number labels its band once per block, on the topmost
|
|
66
65
|
// visible row carrying that segment, so it reads as a column header for the
|
|
67
66
|
// whole band. Keyed by accession rather than drawn on row 0, because the rows
|
|
68
67
|
// carrying the gene model are often not the first ones in the alignment
|
|
69
68
|
const labelled = drawSegmentLabels ? new Set<string>() : undefined
|
|
70
|
-
// gene arrow heads stick out up to a row height past the band, so pad the
|
|
71
|
-
// cull window enough that a band just outside the block still draws its head
|
|
72
|
-
const cull = rowHeight + colWidth
|
|
73
69
|
|
|
74
70
|
drawFeatureSpans<DomainBand>({
|
|
75
71
|
ctx,
|
|
@@ -88,9 +84,11 @@ export function renderBoxFeatureCanvasBlock({
|
|
|
88
84
|
y -
|
|
89
85
|
rowHeight +
|
|
90
86
|
(subFeatureRows ? lane * h : domainUnderline ? rowHeight - h : 0),
|
|
91
|
-
// the head keeps its full size on an underline bar, since a head as short
|
|
92
|
-
// as the bar reads as a nub rather than as a direction
|
|
93
87
|
headLength: h => (domainUnderline ? rowHeight / 2 : h),
|
|
88
|
+
// a head only as tall as an underline bar tapers over ten pixels of
|
|
89
|
+
// three, which reads as nothing; it takes the lower two fifths of the
|
|
90
|
+
// row instead, leaving the letters above it
|
|
91
|
+
headRise: h => (domainUnderline ? Math.max(0, rowHeight * 0.4 - h) : 0),
|
|
94
92
|
},
|
|
95
93
|
xOf: band => [band.startCol * colWidth, band.endCol * colWidth],
|
|
96
94
|
colors: featureColors,
|
|
@@ -101,7 +99,7 @@ export function renderBoxFeatureCanvasBlock({
|
|
|
101
99
|
: undefined),
|
|
102
100
|
labelDrawn: band => labelled?.add(band.annotation.accession),
|
|
103
101
|
contrastText: contrastTextFn(theme),
|
|
104
|
-
xMin: offsetX
|
|
105
|
-
xMax: offsetX + bx
|
|
102
|
+
xMin: offsetX,
|
|
103
|
+
xMax: offsetX + bx,
|
|
106
104
|
})
|
|
107
105
|
}
|