react-msaview 5.0.13 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/index.js +135 -35
- package/bundle/index.js.LICENSE.txt +1 -1
- package/bundle/index.js.map +1 -1
- package/dist/clustalX.d.ts +5 -0
- package/dist/clustalX.js +88 -0
- package/dist/clustalX.js.map +1 -0
- package/dist/components/SequenceTextArea.js +6 -6
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/TextTrack.js +3 -5
- package/dist/components/TextTrack.js.map +1 -1
- package/dist/components/Track.d.ts +2 -1
- package/dist/components/Track.js +4 -3
- package/dist/components/Track.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +6 -31
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.js +5 -3
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.js +4 -2
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/MSASettingsMenu.js +2 -27
- package/dist/components/header/MSASettingsMenu.js.map +1 -1
- package/dist/components/header/SettingsMenu.js +4 -69
- package/dist/components/header/SettingsMenu.js.map +1 -1
- package/dist/components/header/TreeSettingsMenu.js +3 -41
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.d.ts +4 -0
- package/dist/components/header/settingsMenuItems.js +59 -0
- package/dist/components/header/settingsMenuItems.js.map +1 -0
- package/dist/components/import/ImportFormExamples.js +1 -1
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/minimap/Minimap.js +6 -31
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +31 -33
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +15 -9
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +12 -14
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +9 -3
- package/dist/components/tree/renderTreeCanvas.js +29 -14
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/fetchUtils.d.ts +2 -1
- package/dist/fetchUtils.js +16 -2
- package/dist/fetchUtils.js.map +1 -1
- package/dist/hierarchy.d.ts +3 -0
- package/dist/hierarchy.js +25 -0
- package/dist/hierarchy.js.map +1 -1
- package/dist/launchInterProScan.d.ts +2 -1
- package/dist/launchInterProScan.js +31 -15
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/model.d.ts +150 -494
- package/dist/model.js +24 -116
- package/dist/model.js.map +1 -1
- package/dist/useColorContrast.d.ts +10 -0
- package/dist/useColorContrast.js +13 -0
- package/dist/useColorContrast.js.map +1 -0
- package/dist/useDragScroll.d.ts +12 -0
- package/dist/useDragScroll.js +47 -0
- package/dist/useDragScroll.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -6
- package/src/clustalX.test.ts +76 -0
- package/src/clustalX.ts +131 -0
- package/src/components/SequenceTextArea.tsx +6 -6
- package/src/components/TextTrack.tsx +3 -8
- package/src/components/Track.tsx +6 -9
- package/src/components/VerticalScrollbar.tsx +13 -40
- package/src/components/dialogs/InterProScanDialog.tsx +7 -1
- package/src/components/header/HeaderStatusArea.tsx +6 -1
- package/src/components/header/MSASettingsMenu.tsx +3 -27
- package/src/components/header/SettingsMenu.tsx +7 -79
- package/src/components/header/TreeSettingsMenu.tsx +4 -48
- package/src/components/header/settingsMenuItems.ts +68 -0
- package/src/components/import/ImportFormExamples.tsx +1 -1
- package/src/components/minimap/Minimap.tsx +13 -38
- package/src/components/msa/MSACanvasBlock.tsx +53 -36
- package/src/components/msa/renderMSABlock.ts +16 -9
- package/src/components/tree/TreeCanvas.tsx +13 -35
- package/src/components/tree/renderTreeCanvas.test.ts +205 -0
- package/src/components/tree/renderTreeCanvas.ts +46 -11
- package/src/fetchUtils.ts +16 -2
- package/src/hierarchy.ts +28 -0
- package/src/launchInterProScan.ts +34 -10
- package/src/model.ts +33 -143
- package/src/useColorContrast.ts +18 -0
- package/src/useDragScroll.ts +55 -0
- package/src/version.ts +1 -1
package/src/clustalX.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// ClustalX consensus coloring.
|
|
2
|
+
// ref http://www.jalview.org/help/html/colourSchemes/clustal.html
|
|
3
|
+
|
|
4
|
+
const BLUE = 'rgb(128,179,230)'
|
|
5
|
+
const RED = '#d88'
|
|
6
|
+
const MAGENTA_E = 'rgb(192, 72, 192)'
|
|
7
|
+
const MAGENTA_D = 'rgb(204, 77, 204)'
|
|
8
|
+
const GREEN = '#8f8'
|
|
9
|
+
const GREEN_ST = 'rgb(26,204,26)'
|
|
10
|
+
const PINK = 'rgb(240, 128, 128)'
|
|
11
|
+
const ORANGE = 'rgb(240, 144, 72)'
|
|
12
|
+
const YELLOW = 'rgb(204, 204, 0)'
|
|
13
|
+
const CYAN = 'rgb(26, 179, 179)'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Computes the ClustalX letter->color map for a single alignment column given
|
|
17
|
+
* its residue counts (`stats`) and total residue count (`total`).
|
|
18
|
+
*/
|
|
19
|
+
export function clustalXColumnColors(
|
|
20
|
+
stats: Record<string, number>,
|
|
21
|
+
total: number,
|
|
22
|
+
) {
|
|
23
|
+
const {
|
|
24
|
+
W = 0,
|
|
25
|
+
L = 0,
|
|
26
|
+
V = 0,
|
|
27
|
+
I = 0,
|
|
28
|
+
M = 0,
|
|
29
|
+
A = 0,
|
|
30
|
+
F = 0,
|
|
31
|
+
C = 0,
|
|
32
|
+
H = 0,
|
|
33
|
+
P = 0,
|
|
34
|
+
R = 0,
|
|
35
|
+
K = 0,
|
|
36
|
+
Q = 0,
|
|
37
|
+
E = 0,
|
|
38
|
+
D = 0,
|
|
39
|
+
T = 0,
|
|
40
|
+
S = 0,
|
|
41
|
+
G = 0,
|
|
42
|
+
Y = 0,
|
|
43
|
+
N = 0,
|
|
44
|
+
} = stats
|
|
45
|
+
|
|
46
|
+
const hydrophobic = W + L + V + I + M + A + F + C + H + P + Y
|
|
47
|
+
const KR = K + R
|
|
48
|
+
const QE = Q + E
|
|
49
|
+
const ED = E + D
|
|
50
|
+
const TS = T + S
|
|
51
|
+
const p = (n: number) => n / total
|
|
52
|
+
|
|
53
|
+
const colors: Record<string, string> = {}
|
|
54
|
+
|
|
55
|
+
if (p(hydrophobic) > 0.6) {
|
|
56
|
+
colors.W = BLUE
|
|
57
|
+
colors.L = BLUE
|
|
58
|
+
colors.V = BLUE
|
|
59
|
+
colors.A = BLUE
|
|
60
|
+
colors.I = BLUE
|
|
61
|
+
colors.M = BLUE
|
|
62
|
+
colors.F = BLUE
|
|
63
|
+
colors.C = BLUE
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (p(KR) > 0.6 || p(K) > 0.8 || p(R) > 0.8 || p(Q) > 0.8) {
|
|
67
|
+
colors.K = RED
|
|
68
|
+
colors.R = RED
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (p(KR) > 0.6 || p(QE) > 0.5 || p(E) > 0.8 || p(Q) > 0.8 || p(D) > 0.8) {
|
|
72
|
+
colors.E = MAGENTA_E
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (p(KR) > 0.6 || p(ED) > 0.5 || p(K) > 0.8 || p(R) > 0.8 || p(Q) > 0.8) {
|
|
76
|
+
colors.D = MAGENTA_D
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (p(N) > 0.5 || p(Y) > 0.85) {
|
|
80
|
+
colors.N = GREEN
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
p(KR) > 0.6 ||
|
|
85
|
+
p(QE) > 0.6 ||
|
|
86
|
+
p(Q) > 0.85 ||
|
|
87
|
+
p(E) > 0.85 ||
|
|
88
|
+
p(K) > 0.85 ||
|
|
89
|
+
p(R) > 0.85
|
|
90
|
+
) {
|
|
91
|
+
colors.Q = GREEN
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (p(hydrophobic) > 0.6 || p(TS) > 0.5 || p(S) > 0.85 || p(T) > 0.85) {
|
|
95
|
+
colors.S = GREEN_ST
|
|
96
|
+
colors.T = GREEN_ST
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (p(C) > 0.85) {
|
|
100
|
+
colors.C = PINK
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (G > 0) {
|
|
104
|
+
colors.G = ORANGE
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (P > 0) {
|
|
108
|
+
colors.P = YELLOW
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
p(hydrophobic) > 0.6 ||
|
|
113
|
+
p(W) > 0.85 ||
|
|
114
|
+
p(Y) > 0.85 ||
|
|
115
|
+
p(A) > 0.85 ||
|
|
116
|
+
p(C) > 0.85 ||
|
|
117
|
+
p(P) > 0.85 ||
|
|
118
|
+
p(Q) > 0.85 ||
|
|
119
|
+
p(F) > 0.85 ||
|
|
120
|
+
p(H) > 0.85 ||
|
|
121
|
+
p(I) > 0.85 ||
|
|
122
|
+
p(L) > 0.85 ||
|
|
123
|
+
p(M) > 0.85 ||
|
|
124
|
+
p(V) > 0.85
|
|
125
|
+
) {
|
|
126
|
+
colors.H = CYAN
|
|
127
|
+
colors.Y = CYAN
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return colors
|
|
131
|
+
}
|
|
@@ -27,8 +27,8 @@ export default function SequenceTextArea({ str }: { str: [string, string][] }) {
|
|
|
27
27
|
const removeGaps = (s: string) => s.replaceAll('-', '').replaceAll('.', '')
|
|
28
28
|
const disp = str
|
|
29
29
|
.map(([s1, s2]) => [s1, showGaps ? s2 : removeGaps(s2)] as const)
|
|
30
|
-
.filter(
|
|
31
|
-
.map(([s1, s2]) => `>${s1}\n${
|
|
30
|
+
.filter(([, s2]) => showEmpty || !!s2)
|
|
31
|
+
.map(([s1, s2]) => `>${s1}\n${s2}`)
|
|
32
32
|
.join('\n')
|
|
33
33
|
return (
|
|
34
34
|
<>
|
|
@@ -67,10 +67,10 @@ export default function SequenceTextArea({ str }: { str: [string, string][] }) {
|
|
|
67
67
|
maxRows={10}
|
|
68
68
|
fullWidth
|
|
69
69
|
value={disp}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
slotProps={{
|
|
71
|
+
input: {
|
|
72
|
+
readOnly: true,
|
|
73
|
+
className: classes.textAreaFont,
|
|
74
74
|
},
|
|
75
75
|
}}
|
|
76
76
|
/>
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React, { useEffect,
|
|
1
|
+
import React, { useEffect, useRef } from 'react'
|
|
2
2
|
|
|
3
|
-
import { useTheme } from '@mui/material'
|
|
4
3
|
import { observer } from 'mobx-react'
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { useColorContrast } from '../useColorContrast.ts'
|
|
7
6
|
import { drawTextTrackContent } from './tracks/renderTracksSvg.ts'
|
|
8
7
|
|
|
9
8
|
import type { MsaViewModel } from '../model.ts'
|
|
@@ -33,12 +32,8 @@ const AnnotationBlock = observer(function ({
|
|
|
33
32
|
} = track
|
|
34
33
|
|
|
35
34
|
const colorScheme = customColorScheme || modelColorScheme
|
|
36
|
-
const theme = useTheme()
|
|
37
35
|
const ref = useRef<HTMLCanvasElement>(null)
|
|
38
|
-
const contrastScheme =
|
|
39
|
-
() => colorContrast(colorScheme, theme),
|
|
40
|
-
[colorScheme, theme],
|
|
41
|
-
)
|
|
36
|
+
const { contrastScheme } = useColorContrast(colorScheme)
|
|
42
37
|
useEffect(() => {
|
|
43
38
|
if (!ref.current) {
|
|
44
39
|
return
|
package/src/components/Track.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { makeStyles } from 'tss-react/mui'
|
|
|
8
8
|
import { useWheelScroll } from '../useWheelScroll.ts'
|
|
9
9
|
|
|
10
10
|
import type { MsaViewModel } from '../model.ts'
|
|
11
|
+
import type { BasicTrack } from '../types.ts'
|
|
11
12
|
|
|
12
13
|
const TrackInfoDialog = lazy(() => import('./dialogs/TrackInfoDialog.tsx'))
|
|
13
14
|
|
|
@@ -22,7 +23,7 @@ const TrackLabel = observer(function TrackLabel({
|
|
|
22
23
|
track,
|
|
23
24
|
}: {
|
|
24
25
|
model: MsaViewModel
|
|
25
|
-
track:
|
|
26
|
+
track: BasicTrack
|
|
26
27
|
}) {
|
|
27
28
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>()
|
|
28
29
|
const { drawLabels, rowHeight, treeAreaWidth: width } = model
|
|
@@ -96,11 +97,11 @@ const Track = observer(function ({
|
|
|
96
97
|
track,
|
|
97
98
|
}: {
|
|
98
99
|
model: MsaViewModel
|
|
99
|
-
track:
|
|
100
|
+
track: BasicTrack
|
|
100
101
|
}) {
|
|
101
102
|
const { resizeHandleWidth, colWidth, scrollX, numColumns } = model
|
|
102
103
|
const {
|
|
103
|
-
model: { height
|
|
104
|
+
model: { height },
|
|
104
105
|
} = track
|
|
105
106
|
const ref = useRef<HTMLDivElement>(null)
|
|
106
107
|
const onScrollX = useCallback(
|
|
@@ -112,7 +113,7 @@ const Track = observer(function ({
|
|
|
112
113
|
useWheelScroll({ ref, onScrollX })
|
|
113
114
|
|
|
114
115
|
return (
|
|
115
|
-
<div
|
|
116
|
+
<div style={{ display: 'flex', height }}>
|
|
116
117
|
<TrackLabel model={model} track={track} />
|
|
117
118
|
<div style={{ width: resizeHandleWidth, flexShrink: 0 }} />
|
|
118
119
|
<div
|
|
@@ -134,11 +135,7 @@ const Track = observer(function ({
|
|
|
134
135
|
model.setMousePos(undefined, undefined)
|
|
135
136
|
}}
|
|
136
137
|
>
|
|
137
|
-
{
|
|
138
|
-
<div style={{ color: 'red', fontSize: 10 }}>{`${error}`}</div>
|
|
139
|
-
) : (
|
|
140
|
-
<track.ReactComponent model={model} track={track} />
|
|
141
|
-
)}
|
|
138
|
+
<track.ReactComponent model={model} track={track} />
|
|
142
139
|
</div>
|
|
143
140
|
</div>
|
|
144
141
|
)
|
|
@@ -1,54 +1,30 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { clamp } from '@jbrowse/core/util'
|
|
4
4
|
import { observer } from 'mobx-react'
|
|
5
5
|
|
|
6
|
+
import { useDragScroll } from '../useDragScroll.ts'
|
|
7
|
+
|
|
6
8
|
import type { MsaViewModel } from '../model.ts'
|
|
7
9
|
|
|
8
10
|
const VerticalScrollbar = observer(({ model }: { model: MsaViewModel }) => {
|
|
9
11
|
const { msaAreaHeight, scrollY, totalHeight } = model
|
|
10
12
|
const [hovered, setHovered] = useState(false)
|
|
11
|
-
const scheduled = useRef(false)
|
|
12
|
-
const [mouseDown, setMouseDown] = useState<{
|
|
13
|
-
clientY: number
|
|
14
|
-
scrollY: number
|
|
15
|
-
}>()
|
|
16
13
|
const fill = 'rgba(66, 119, 127, 0.3)'
|
|
17
14
|
const unit = msaAreaHeight / totalHeight
|
|
18
15
|
const top = -scrollY
|
|
19
16
|
const bottom = top + msaAreaHeight
|
|
20
17
|
const t = top * unit
|
|
21
18
|
const b = bottom * unit
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-totalHeight,
|
|
32
|
-
0,
|
|
33
|
-
),
|
|
34
|
-
)
|
|
35
|
-
scheduled.current = false
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function fn2() {
|
|
41
|
-
setMouseDown(undefined)
|
|
42
|
-
}
|
|
43
|
-
if (mouseDown !== undefined) {
|
|
44
|
-
document.addEventListener('mousemove', fn)
|
|
45
|
-
document.addEventListener('mouseup', fn2)
|
|
46
|
-
return () => {
|
|
47
|
-
document.removeEventListener('mousemove', fn)
|
|
48
|
-
document.removeEventListener('mousemove', fn2)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}, [model, unit, totalHeight, mouseDown])
|
|
19
|
+
const { startDrag } = useDragScroll(
|
|
20
|
+
'y',
|
|
21
|
+
useCallback(
|
|
22
|
+
(delta: number, startScroll: number) => {
|
|
23
|
+
model.setScrollY(clamp(startScroll - delta / unit, -totalHeight, 0))
|
|
24
|
+
},
|
|
25
|
+
[model, unit, totalHeight],
|
|
26
|
+
),
|
|
27
|
+
)
|
|
52
28
|
return (
|
|
53
29
|
<div
|
|
54
30
|
style={{
|
|
@@ -79,10 +55,7 @@ const VerticalScrollbar = observer(({ model }: { model: MsaViewModel }) => {
|
|
|
79
55
|
setHovered(false)
|
|
80
56
|
}}
|
|
81
57
|
onMouseDown={event => {
|
|
82
|
-
|
|
83
|
-
clientY: event.clientY,
|
|
84
|
-
scrollY: model.scrollY,
|
|
85
|
-
})
|
|
58
|
+
startDrag(event, model.scrollY)
|
|
86
59
|
}}
|
|
87
60
|
/>
|
|
88
61
|
</div>
|
|
@@ -237,6 +237,7 @@ const InterProScanDialog = observer(function ({
|
|
|
237
237
|
variant="contained"
|
|
238
238
|
color="primary"
|
|
239
239
|
onClick={() => {
|
|
240
|
+
const controller = new AbortController()
|
|
240
241
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
241
242
|
;(async () => {
|
|
242
243
|
try {
|
|
@@ -255,9 +256,14 @@ const InterProScanDialog = observer(function ({
|
|
|
255
256
|
.map(row => `>${row[0]}\n${row[1]}`)
|
|
256
257
|
.join('\n'),
|
|
257
258
|
onProgress: arg => {
|
|
258
|
-
model.setStatus(
|
|
259
|
+
model.setStatus(
|
|
260
|
+
arg
|
|
261
|
+
? { ...arg, onCancel: () => { controller.abort() } }
|
|
262
|
+
: undefined,
|
|
263
|
+
)
|
|
259
264
|
},
|
|
260
265
|
model,
|
|
266
|
+
signal: controller.signal,
|
|
261
267
|
})
|
|
262
268
|
} catch (e) {
|
|
263
269
|
console.error(e)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
3
|
import { LoadingEllipses } from '@jbrowse/core/ui'
|
|
4
|
-
import { Typography } from '@mui/material'
|
|
4
|
+
import { Button, Typography } from '@mui/material'
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
import { makeStyles } from 'tss-react/mui'
|
|
7
7
|
|
|
@@ -24,6 +24,11 @@ const HeaderStatusArea = observer(({ model }: { model: MsaViewModel }) => {
|
|
|
24
24
|
<a href={status.url} target="_blank" rel="noreferrer">
|
|
25
25
|
(status)
|
|
26
26
|
</a>
|
|
27
|
+
) : null}{' '}
|
|
28
|
+
{status.onCancel ? (
|
|
29
|
+
<Button size="small" onClick={() => status.onCancel?.()}>
|
|
30
|
+
Cancel
|
|
31
|
+
</Button>
|
|
27
32
|
) : null}
|
|
28
33
|
</Typography>
|
|
29
34
|
) : null
|
|
@@ -4,41 +4,17 @@ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
|
|
|
4
4
|
import Tune from '@mui/icons-material/Tune'
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
|
|
7
|
+
import { msaSettingsMenuItems } from './settingsMenuItems.ts'
|
|
8
|
+
|
|
7
9
|
import type { MsaViewModel } from '../../model.ts'
|
|
8
10
|
|
|
9
11
|
const MSASettingsMenu = observer(function ({ model }: { model: MsaViewModel }) {
|
|
10
|
-
const { drawMsaLetters, hideGaps, bgColor } = model
|
|
11
12
|
return (
|
|
12
13
|
<CascadingMenuButton
|
|
13
14
|
closeAfterItemClick={false}
|
|
14
15
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
|
15
16
|
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
|
|
16
|
-
menuItems={
|
|
17
|
-
{
|
|
18
|
-
label: 'Draw letters',
|
|
19
|
-
type: 'checkbox',
|
|
20
|
-
checked: drawMsaLetters,
|
|
21
|
-
onClick: () => {
|
|
22
|
-
model.setDrawMsaLetters(!drawMsaLetters)
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
label: 'Color letters instead of background of tiles',
|
|
27
|
-
type: 'checkbox',
|
|
28
|
-
checked: !bgColor,
|
|
29
|
-
onClick: () => {
|
|
30
|
-
model.setBgColor(!bgColor)
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
label: 'Enable hiding gappy columns?',
|
|
35
|
-
type: 'checkbox',
|
|
36
|
-
checked: hideGaps,
|
|
37
|
-
onClick: () => {
|
|
38
|
-
model.setHideGaps(!hideGaps)
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
]}
|
|
17
|
+
menuItems={msaSettingsMenuItems(model)}
|
|
42
18
|
>
|
|
43
19
|
<Tune />
|
|
44
20
|
</CascadingMenuButton>
|
|
@@ -6,22 +6,16 @@ import Palette from '@mui/icons-material/Palette'
|
|
|
6
6
|
import Settings from '@mui/icons-material/Settings'
|
|
7
7
|
import { observer } from 'mobx-react'
|
|
8
8
|
|
|
9
|
+
import {
|
|
10
|
+
msaSettingsMenuItems,
|
|
11
|
+
treeSettingsMenuItems,
|
|
12
|
+
} from './settingsMenuItems.ts'
|
|
9
13
|
import colorSchemes from '../../colorSchemes.ts'
|
|
10
14
|
|
|
11
15
|
import type { MsaViewModel } from '../../model.ts'
|
|
12
16
|
|
|
13
17
|
const SettingsMenu = observer(function ({ model }: { model: MsaViewModel }) {
|
|
14
|
-
const {
|
|
15
|
-
colorSchemeName,
|
|
16
|
-
drawMsaLetters,
|
|
17
|
-
hideGaps,
|
|
18
|
-
bgColor,
|
|
19
|
-
drawTree,
|
|
20
|
-
showBranchLen,
|
|
21
|
-
labelsAlignRight,
|
|
22
|
-
drawNodeBubbles,
|
|
23
|
-
drawLabels,
|
|
24
|
-
} = model
|
|
18
|
+
const { colorSchemeName } = model
|
|
25
19
|
return (
|
|
26
20
|
<CascadingMenuButton
|
|
27
21
|
closeAfterItemClick={false}
|
|
@@ -45,79 +39,13 @@ const SettingsMenu = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
45
39
|
{
|
|
46
40
|
label: 'MSA settings',
|
|
47
41
|
type: 'subMenu',
|
|
48
|
-
subMenu:
|
|
49
|
-
{
|
|
50
|
-
label: 'Draw letters',
|
|
51
|
-
type: 'checkbox',
|
|
52
|
-
checked: drawMsaLetters,
|
|
53
|
-
onClick: () => {
|
|
54
|
-
model.setDrawMsaLetters(!drawMsaLetters)
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
label: 'Color letters instead of background of tiles',
|
|
59
|
-
type: 'checkbox',
|
|
60
|
-
checked: !bgColor,
|
|
61
|
-
onClick: () => {
|
|
62
|
-
model.setBgColor(!bgColor)
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
label: 'Enable hiding gappy columns?',
|
|
67
|
-
type: 'checkbox',
|
|
68
|
-
checked: hideGaps,
|
|
69
|
-
onClick: () => {
|
|
70
|
-
model.setHideGaps(!hideGaps)
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
],
|
|
42
|
+
subMenu: msaSettingsMenuItems(model),
|
|
74
43
|
},
|
|
75
44
|
{
|
|
76
45
|
label: 'Tree settings',
|
|
77
46
|
type: 'subMenu',
|
|
78
47
|
icon: AccountTree,
|
|
79
|
-
subMenu:
|
|
80
|
-
{
|
|
81
|
-
label: 'Show branch length',
|
|
82
|
-
type: 'checkbox',
|
|
83
|
-
checked: showBranchLen,
|
|
84
|
-
onClick: () => {
|
|
85
|
-
model.setShowBranchLen(!showBranchLen)
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
label: 'Show tree',
|
|
90
|
-
type: 'checkbox',
|
|
91
|
-
checked: drawTree,
|
|
92
|
-
onClick: () => {
|
|
93
|
-
model.setDrawTree(!drawTree)
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
label: 'Draw clickable bubbles on tree branches',
|
|
98
|
-
type: 'checkbox',
|
|
99
|
-
checked: drawNodeBubbles,
|
|
100
|
-
onClick: () => {
|
|
101
|
-
model.setDrawNodeBubbles(!drawNodeBubbles)
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
label: 'Tree labels align right',
|
|
106
|
-
type: 'checkbox',
|
|
107
|
-
checked: labelsAlignRight,
|
|
108
|
-
onClick: () => {
|
|
109
|
-
model.setLabelsAlignRight(!labelsAlignRight)
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
label: 'Draw labels',
|
|
114
|
-
type: 'checkbox',
|
|
115
|
-
checked: drawLabels,
|
|
116
|
-
onClick: () => {
|
|
117
|
-
model.setDrawLabels(!drawLabels)
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
],
|
|
48
|
+
subMenu: treeSettingsMenuItems(model),
|
|
121
49
|
},
|
|
122
50
|
]}
|
|
123
51
|
>
|
|
@@ -4,6 +4,8 @@ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
|
|
|
4
4
|
import AccountTree from '@mui/icons-material/AccountTree'
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
|
|
7
|
+
import { treeSettingsMenuItems } from './settingsMenuItems.ts'
|
|
8
|
+
|
|
7
9
|
import type { MsaViewModel } from '../../model.ts'
|
|
8
10
|
|
|
9
11
|
const TreeSettingsMenu = observer(function ({
|
|
@@ -11,60 +13,14 @@ const TreeSettingsMenu = observer(function ({
|
|
|
11
13
|
}: {
|
|
12
14
|
model: MsaViewModel
|
|
13
15
|
}) {
|
|
14
|
-
const {
|
|
15
|
-
drawTree,
|
|
16
|
-
showBranchLen,
|
|
17
|
-
labelsAlignRight,
|
|
18
|
-
drawNodeBubbles,
|
|
19
|
-
drawLabels,
|
|
20
|
-
rows,
|
|
21
|
-
} = model
|
|
16
|
+
const { rows } = model
|
|
22
17
|
return (
|
|
23
18
|
<CascadingMenuButton
|
|
24
19
|
closeAfterItemClick={false}
|
|
25
20
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
|
26
21
|
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
|
|
27
22
|
menuItems={[
|
|
28
|
-
|
|
29
|
-
label: 'Show branch length',
|
|
30
|
-
type: 'checkbox',
|
|
31
|
-
checked: showBranchLen,
|
|
32
|
-
onClick: () => {
|
|
33
|
-
model.setShowBranchLen(!showBranchLen)
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
label: 'Show tree',
|
|
38
|
-
type: 'checkbox',
|
|
39
|
-
checked: drawTree,
|
|
40
|
-
onClick: () => {
|
|
41
|
-
model.setDrawTree(!drawTree)
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
label: 'Draw clickable bubbles on tree branches',
|
|
46
|
-
type: 'checkbox',
|
|
47
|
-
checked: drawNodeBubbles,
|
|
48
|
-
onClick: () => {
|
|
49
|
-
model.setDrawNodeBubbles(!drawNodeBubbles)
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
label: 'Tree labels align right',
|
|
54
|
-
type: 'checkbox',
|
|
55
|
-
checked: labelsAlignRight,
|
|
56
|
-
onClick: () => {
|
|
57
|
-
model.setLabelsAlignRight(!labelsAlignRight)
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
label: 'Draw labels',
|
|
62
|
-
type: 'checkbox',
|
|
63
|
-
checked: drawLabels,
|
|
64
|
-
onClick: () => {
|
|
65
|
-
model.setDrawLabels(!drawLabels)
|
|
66
|
-
},
|
|
67
|
-
},
|
|
23
|
+
...treeSettingsMenuItems(model),
|
|
68
24
|
...(rows.length >= 2
|
|
69
25
|
? [
|
|
70
26
|
{
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
2
|
+
import type { MenuItem } from '@jbrowse/core/ui/Menu'
|
|
3
|
+
|
|
4
|
+
export function msaSettingsMenuItems(model: MsaViewModel): MenuItem[] {
|
|
5
|
+
const { drawMsaLetters, hideGaps, bgColor } = model
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
label: 'Draw letters',
|
|
9
|
+
type: 'checkbox',
|
|
10
|
+
checked: drawMsaLetters,
|
|
11
|
+
onClick: () => { model.setDrawMsaLetters(!drawMsaLetters) },
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: 'Color letters instead of background of tiles',
|
|
15
|
+
type: 'checkbox',
|
|
16
|
+
checked: !bgColor,
|
|
17
|
+
onClick: () => { model.setBgColor(!bgColor) },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: 'Enable hiding gappy columns?',
|
|
21
|
+
type: 'checkbox',
|
|
22
|
+
checked: hideGaps,
|
|
23
|
+
onClick: () => { model.setHideGaps(!hideGaps) },
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function treeSettingsMenuItems(model: MsaViewModel): MenuItem[] {
|
|
29
|
+
const {
|
|
30
|
+
drawTree,
|
|
31
|
+
showBranchLen,
|
|
32
|
+
labelsAlignRight,
|
|
33
|
+
drawNodeBubbles,
|
|
34
|
+
drawLabels,
|
|
35
|
+
} = model
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
label: 'Show branch length',
|
|
39
|
+
type: 'checkbox',
|
|
40
|
+
checked: showBranchLen,
|
|
41
|
+
onClick: () => { model.setShowBranchLen(!showBranchLen) },
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'Show tree',
|
|
45
|
+
type: 'checkbox',
|
|
46
|
+
checked: drawTree,
|
|
47
|
+
onClick: () => { model.setDrawTree(!drawTree) },
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: 'Draw clickable bubbles on tree branches',
|
|
51
|
+
type: 'checkbox',
|
|
52
|
+
checked: drawNodeBubbles,
|
|
53
|
+
onClick: () => { model.setDrawNodeBubbles(!drawNodeBubbles) },
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: 'Tree labels align right',
|
|
57
|
+
type: 'checkbox',
|
|
58
|
+
checked: labelsAlignRight,
|
|
59
|
+
onClick: () => { model.setLabelsAlignRight(!labelsAlignRight) },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
label: 'Draw labels',
|
|
63
|
+
type: 'checkbox',
|
|
64
|
+
checked: drawLabels,
|
|
65
|
+
onClick: () => { model.setDrawLabels(!drawLabels) },
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
}
|