react-msaview 3.0.0 → 3.0.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 +31 -31
- package/dist/components/Header.js +4 -9
- package/dist/components/Header.js.map +1 -1
- package/dist/components/HeaderInfoArea.d.ts +6 -0
- package/dist/components/HeaderInfoArea.js +12 -0
- package/dist/components/HeaderInfoArea.js.map +1 -0
- package/dist/components/MSAPanel/Loading.d.ts +2 -0
- package/dist/components/MSAPanel/Loading.js +12 -0
- package/dist/components/MSAPanel/Loading.js.map +1 -0
- package/dist/components/MSAPanel/MSACanvas.js +1 -10
- package/dist/components/MSAPanel/MSACanvas.js.map +1 -1
- package/dist/components/MSAPanel/MSAMouseoverCanvas.js +1 -22
- package/dist/components/MSAPanel/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/MSAPanel/renderMSABlock.js +0 -1
- package/dist/components/MSAPanel/renderMSABlock.js.map +1 -1
- package/dist/components/MSAPanel/renderMSAMouseover.d.ts +5 -0
- package/dist/components/MSAPanel/renderMSAMouseover.js +24 -0
- package/dist/components/MSAPanel/renderMSAMouseover.js.map +1 -0
- package/dist/components/Minimap.js +13 -13
- package/dist/components/Minimap.js.map +1 -1
- package/dist/components/TreePanel/TreeCanvasBlock.js +8 -4
- package/dist/components/TreePanel/TreeCanvasBlock.js.map +1 -1
- package/dist/components/TreePanel/{TreeMenu.d.ts → TreeNodeMenu.d.ts} +1 -0
- package/dist/components/TreePanel/{TreeMenu.js → TreeNodeMenu.js} +8 -4
- package/dist/components/TreePanel/TreeNodeMenu.js.map +1 -0
- package/dist/components/TreePanel/dialogs/{TreeNodeInfoDlg.js → TreeNodeInfoDialog.js} +2 -2
- package/dist/components/TreePanel/dialogs/TreeNodeInfoDialog.js.map +1 -0
- package/dist/components/TreePanel/renderTreeCanvas.d.ts +8 -3
- package/dist/components/TreePanel/renderTreeCanvas.js +8 -7
- package/dist/components/TreePanel/renderTreeCanvas.js.map +1 -1
- package/dist/components/dialogs/SettingsDialog.js +31 -22
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/model.d.ts +120 -62
- package/dist/model.js +176 -124
- package/dist/model.js.map +1 -1
- package/dist/parsers/ClustalMSA.d.ts +1 -1
- package/dist/parsers/ClustalMSA.js +1 -1
- package/dist/parsers/ClustalMSA.js.map +1 -1
- package/dist/parsers/FastaMSA.d.ts +1 -1
- package/dist/parsers/FastaMSA.js +2 -2
- package/dist/parsers/FastaMSA.js.map +1 -1
- package/dist/parsers/StockholmMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.js +2 -2
- package/dist/parsers/StockholmMSA.js.map +1 -1
- package/dist/util.d.ts +1 -0
- package/dist/util.js +15 -7
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/components/Header.tsx +5 -11
- package/src/components/HeaderInfoArea.tsx +21 -0
- package/src/components/MSAPanel/Loading.tsx +16 -0
- package/src/components/MSAPanel/MSACanvas.tsx +1 -16
- package/src/components/MSAPanel/MSAMouseoverCanvas.tsx +2 -50
- package/src/components/MSAPanel/renderMSABlock.ts +0 -2
- package/src/components/MSAPanel/renderMSAMouseover.ts +51 -0
- package/src/components/Minimap.tsx +15 -15
- package/src/components/TreePanel/TreeCanvasBlock.tsx +8 -3
- package/src/components/TreePanel/{TreeMenu.tsx → TreeNodeMenu.tsx} +12 -3
- package/src/components/TreePanel/dialogs/{TreeNodeInfoDlg.tsx → TreeNodeInfoDialog.tsx} +1 -1
- package/src/components/TreePanel/renderTreeCanvas.ts +13 -4
- package/src/components/dialogs/SettingsDialog.tsx +61 -44
- package/src/model.ts +279 -154
- package/src/parsers/ClustalMSA.ts +1 -1
- package/src/parsers/FastaMSA.ts +1 -1
- package/src/parsers/StockholmMSA.ts +1 -1
- package/src/util.ts +19 -6
- package/src/version.ts +1 -1
- package/dist/components/OverviewRubberband.d.ts +0 -8
- package/dist/components/OverviewRubberband.js +0 -185
- package/dist/components/OverviewRubberband.js.map +0 -1
- package/dist/components/Rubberband.d.ts +0 -8
- package/dist/components/Rubberband.js +0 -185
- package/dist/components/Rubberband.js.map +0 -1
- package/dist/components/TreePanel/TreeMenu.js.map +0 -1
- package/dist/components/TreePanel/dialogs/TreeNodeInfoDlg.js.map +0 -1
- package/dist/components/dialogs/AnnotationDialog.d.ts +0 -11
- package/dist/components/dialogs/AnnotationDialog.js +0 -65
- package/dist/components/dialogs/AnnotationDialog.js.map +0 -1
- package/src/components/OverviewRubberband.tsx +0 -283
- package/src/components/Rubberband.tsx +0 -283
- package/src/components/dialogs/AnnotationDialog.tsx +0 -144
- /package/dist/components/TreePanel/dialogs/{TreeNodeInfoDlg.d.ts → TreeNodeInfoDialog.d.ts} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { autorun } from 'mobx'
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
|
+
import { useTheme } from '@mui/material'
|
|
4
5
|
import RBush from 'rbush'
|
|
5
6
|
|
|
6
7
|
// locals
|
|
7
8
|
import { MsaViewModel } from '../../model'
|
|
8
|
-
import
|
|
9
|
+
import TreeNodeMenu from './TreeNodeMenu'
|
|
9
10
|
import TreeBranchMenu from './TreeBranchMenu'
|
|
10
11
|
import { padding, renderTreeCanvas } from './renderTreeCanvas'
|
|
11
12
|
|
|
@@ -33,6 +34,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
33
34
|
model: MsaViewModel
|
|
34
35
|
offsetY: number
|
|
35
36
|
}) {
|
|
37
|
+
const theme = useTheme()
|
|
36
38
|
const ref = useRef<HTMLCanvasElement>()
|
|
37
39
|
const clickMap = useRef(new RBush<ClickEntry>())
|
|
38
40
|
const mouseoverRef = useRef<HTMLCanvasElement>(null)
|
|
@@ -68,9 +70,10 @@ const TreeCanvasBlock = observer(function ({
|
|
|
68
70
|
model,
|
|
69
71
|
offsetY,
|
|
70
72
|
clickMap: clickMap.current,
|
|
73
|
+
theme,
|
|
71
74
|
})
|
|
72
75
|
})
|
|
73
|
-
}, [model, offsetY])
|
|
76
|
+
}, [model, offsetY, theme])
|
|
74
77
|
|
|
75
78
|
useEffect(() => {
|
|
76
79
|
const ctx = mouseoverRef.current?.getContext('2d')
|
|
@@ -138,7 +141,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
138
141
|
) : null}
|
|
139
142
|
|
|
140
143
|
{toggleNodeMenu?.id ? (
|
|
141
|
-
<
|
|
144
|
+
<TreeNodeMenu
|
|
142
145
|
node={toggleNodeMenu}
|
|
143
146
|
model={model}
|
|
144
147
|
onClose={() => setToggleNodeMenu(undefined)}
|
|
@@ -155,6 +158,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
155
158
|
}
|
|
156
159
|
|
|
157
160
|
const ret = hoverNameClickMap(event) || hoverBranchClickMap(event)
|
|
161
|
+
console.log({ ret })
|
|
158
162
|
ref.current.style.cursor = ret ? 'pointer' : 'default'
|
|
159
163
|
setHoverElt(hoverNameClickMap(event))
|
|
160
164
|
}}
|
|
@@ -171,6 +175,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
171
175
|
setToggleNodeMenu({ ...data2, x, y })
|
|
172
176
|
}
|
|
173
177
|
}}
|
|
178
|
+
onMouseLeave={() => setHoverElt(undefined)}
|
|
174
179
|
ref={vref}
|
|
175
180
|
/>
|
|
176
181
|
<canvas
|
|
@@ -5,14 +5,14 @@ import { observer } from 'mobx-react'
|
|
|
5
5
|
// locals
|
|
6
6
|
import { MsaViewModel } from '../../model'
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const TreeNodeInfoDialog = lazy(() => import('./dialogs/TreeNodeInfoDialog'))
|
|
9
9
|
|
|
10
10
|
const TreeMenu = observer(function ({
|
|
11
11
|
node,
|
|
12
12
|
onClose,
|
|
13
13
|
model,
|
|
14
14
|
}: {
|
|
15
|
-
node: { x: number; y: number; name: string }
|
|
15
|
+
node: { x: number; y: number; name: string; id: string }
|
|
16
16
|
model: MsaViewModel
|
|
17
17
|
onClose: () => void
|
|
18
18
|
}) {
|
|
@@ -40,7 +40,7 @@ const TreeMenu = observer(function ({
|
|
|
40
40
|
dense
|
|
41
41
|
onClick={() => {
|
|
42
42
|
model.queueDialog(onClose => [
|
|
43
|
-
|
|
43
|
+
TreeNodeInfoDialog,
|
|
44
44
|
{
|
|
45
45
|
info: model.getRowData(node.name),
|
|
46
46
|
model,
|
|
@@ -53,6 +53,15 @@ const TreeMenu = observer(function ({
|
|
|
53
53
|
>
|
|
54
54
|
More info...
|
|
55
55
|
</MenuItem>
|
|
56
|
+
<MenuItem
|
|
57
|
+
dense
|
|
58
|
+
onClick={() => {
|
|
59
|
+
model.hideNode(node.id)
|
|
60
|
+
onClose()
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
63
|
+
Hide node
|
|
64
|
+
</MenuItem>
|
|
56
65
|
|
|
57
66
|
{structures[node.name]?.map(entry => {
|
|
58
67
|
return !model.selectedStructures.some(n => n.id === node.name) ? (
|
|
@@ -25,7 +25,7 @@ export default observer(function ({
|
|
|
25
25
|
<Dialog onClose={() => onClose()} open title="Tree node info">
|
|
26
26
|
<DialogContent>
|
|
27
27
|
<BaseCard title="Attributes">
|
|
28
|
-
<Attributes attributes={info} />
|
|
28
|
+
<Attributes attributes={{ nodeName, ...info }} />
|
|
29
29
|
</BaseCard>
|
|
30
30
|
{metadata ? (
|
|
31
31
|
<BaseCard title="Extra metadata">
|
|
@@ -2,6 +2,7 @@ import RBush from 'rbush'
|
|
|
2
2
|
|
|
3
3
|
// locals
|
|
4
4
|
import { MsaViewModel } from '../../model'
|
|
5
|
+
import { Theme } from '@mui/material'
|
|
5
6
|
|
|
6
7
|
export const padding = 600
|
|
7
8
|
const extendBounds = 5
|
|
@@ -22,12 +23,15 @@ export function renderTree({
|
|
|
22
23
|
offsetY,
|
|
23
24
|
ctx,
|
|
24
25
|
model,
|
|
26
|
+
theme,
|
|
25
27
|
}: {
|
|
26
28
|
offsetY: number
|
|
27
29
|
ctx: CanvasRenderingContext2D
|
|
28
30
|
model: MsaViewModel
|
|
31
|
+
theme: Theme
|
|
29
32
|
}) {
|
|
30
33
|
const { hierarchy, showBranchLen, blockSize } = model
|
|
34
|
+
ctx.strokeStyle = theme.palette.text.primary
|
|
31
35
|
for (const { source, target } of hierarchy.links()) {
|
|
32
36
|
const y = showBranchLen ? 'len' : 'y'
|
|
33
37
|
// @ts-expect-error
|
|
@@ -60,6 +64,7 @@ export function renderNodeBubbles({
|
|
|
60
64
|
clickMap: RBush<ClickEntry>
|
|
61
65
|
offsetY: number
|
|
62
66
|
model: MsaViewModel
|
|
67
|
+
theme: Theme
|
|
63
68
|
}) {
|
|
64
69
|
const { hierarchy, showBranchLen, collapsed, blockSize } = model
|
|
65
70
|
for (const node of hierarchy.descendants()) {
|
|
@@ -98,6 +103,7 @@ export function renderNodeBubbles({
|
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
export function renderTreeLabels({
|
|
106
|
+
theme,
|
|
101
107
|
model,
|
|
102
108
|
offsetY,
|
|
103
109
|
ctx,
|
|
@@ -107,6 +113,7 @@ export function renderTreeLabels({
|
|
|
107
113
|
offsetY: number
|
|
108
114
|
ctx: CanvasRenderingContext2D
|
|
109
115
|
clickMap: RBush<ClickEntry>
|
|
116
|
+
theme: Theme
|
|
110
117
|
}) {
|
|
111
118
|
const {
|
|
112
119
|
rowHeight,
|
|
@@ -149,7 +156,7 @@ export function renderTreeLabels({
|
|
|
149
156
|
const height = ctx.measureText('M').width // use an 'em' for height
|
|
150
157
|
|
|
151
158
|
const hasStructure = structures[name]
|
|
152
|
-
ctx.fillStyle = hasStructure ? 'blue' :
|
|
159
|
+
ctx.fillStyle = hasStructure ? 'blue' : theme.palette.text.primary
|
|
153
160
|
|
|
154
161
|
if (!drawTree && !labelsAlignRight) {
|
|
155
162
|
ctx.fillText(displayName, 0, yp)
|
|
@@ -200,11 +207,13 @@ export function renderTreeCanvas({
|
|
|
200
207
|
clickMap,
|
|
201
208
|
ctx,
|
|
202
209
|
offsetY,
|
|
210
|
+
theme,
|
|
203
211
|
}: {
|
|
204
212
|
model: MsaViewModel
|
|
205
213
|
offsetY: number
|
|
206
214
|
ctx: CanvasRenderingContext2D
|
|
207
215
|
clickMap: RBush<ClickEntry>
|
|
216
|
+
theme: Theme
|
|
208
217
|
}) {
|
|
209
218
|
clickMap.clear()
|
|
210
219
|
const {
|
|
@@ -232,14 +241,14 @@ export function renderTreeCanvas({
|
|
|
232
241
|
ctx.font = font.replace(/\d+px/, `${fontSize}px`)
|
|
233
242
|
|
|
234
243
|
if (!noTree && drawTree) {
|
|
235
|
-
renderTree({ ctx, offsetY, model })
|
|
244
|
+
renderTree({ ctx, offsetY, model, theme })
|
|
236
245
|
|
|
237
246
|
if (drawNodeBubbles) {
|
|
238
|
-
renderNodeBubbles({ ctx, offsetY, clickMap, model })
|
|
247
|
+
renderNodeBubbles({ ctx, offsetY, clickMap, model, theme })
|
|
239
248
|
}
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
if (rowHeight >= 5) {
|
|
243
|
-
renderTreeLabels({ ctx, offsetY, model, clickMap })
|
|
252
|
+
renderTreeLabels({ ctx, offsetY, model, clickMap, theme })
|
|
244
253
|
}
|
|
245
254
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DialogActions,
|
|
9
9
|
DialogContent,
|
|
10
10
|
FormControlLabel,
|
|
11
|
+
FormControlLabelProps,
|
|
11
12
|
MenuItem,
|
|
12
13
|
Slider,
|
|
13
14
|
TextField,
|
|
@@ -21,15 +22,20 @@ const useStyles = makeStyles()(theme => ({
|
|
|
21
22
|
field: {
|
|
22
23
|
margin: theme.spacing(4),
|
|
23
24
|
},
|
|
25
|
+
flex: {
|
|
26
|
+
display: 'flex',
|
|
27
|
+
},
|
|
24
28
|
}))
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
30
|
+
function FormControlLabel2(rest: FormControlLabelProps) {
|
|
31
|
+
return (
|
|
32
|
+
<div>
|
|
33
|
+
<FormControlLabel {...rest} />
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const SettingsContent = observer(function ({ model }: { model: MsaViewModel }) {
|
|
33
39
|
const { classes } = useStyles()
|
|
34
40
|
const {
|
|
35
41
|
bgColor,
|
|
@@ -44,59 +50,52 @@ const SettingsDialog = observer(function ({
|
|
|
44
50
|
treeWidthMatchesArea,
|
|
45
51
|
treeWidth,
|
|
46
52
|
} = model
|
|
47
|
-
|
|
48
53
|
return (
|
|
49
|
-
|
|
50
|
-
<
|
|
51
|
-
<
|
|
54
|
+
<>
|
|
55
|
+
<div>
|
|
56
|
+
<Button onClick={() => model.clearHidden()}>Clear hidden</Button>
|
|
57
|
+
<h1>Tree options</h1>
|
|
58
|
+
<FormControlLabel2
|
|
52
59
|
control={
|
|
53
60
|
<Checkbox
|
|
54
61
|
checked={showBranchLen}
|
|
55
62
|
onChange={() => model.setShowBranchLen(!showBranchLen)}
|
|
56
63
|
/>
|
|
57
64
|
}
|
|
58
|
-
label="Show branch length"
|
|
65
|
+
label="Show branch length?"
|
|
59
66
|
/>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<Checkbox
|
|
63
|
-
checked={bgColor}
|
|
64
|
-
onChange={() => model.setBgColor(!bgColor)}
|
|
65
|
-
/>
|
|
66
|
-
}
|
|
67
|
-
label="Color background"
|
|
68
|
-
/>
|
|
69
|
-
<FormControlLabel
|
|
67
|
+
|
|
68
|
+
<FormControlLabel2
|
|
70
69
|
control={
|
|
71
70
|
<Checkbox
|
|
72
71
|
checked={drawNodeBubbles}
|
|
73
72
|
onChange={() => model.setDrawNodeBubbles(!drawNodeBubbles)}
|
|
74
73
|
/>
|
|
75
74
|
}
|
|
76
|
-
label="Draw
|
|
75
|
+
label="Draw clickable bubbles on tree branches?"
|
|
77
76
|
/>
|
|
78
|
-
<
|
|
77
|
+
<FormControlLabel2
|
|
79
78
|
control={
|
|
80
79
|
<Checkbox
|
|
81
80
|
checked={drawTree}
|
|
82
81
|
onChange={() => model.setDrawTree(!drawTree)}
|
|
83
82
|
/>
|
|
84
83
|
}
|
|
85
|
-
label="
|
|
84
|
+
label="Show tree?"
|
|
86
85
|
/>
|
|
87
|
-
|
|
86
|
+
|
|
87
|
+
<FormControlLabel2
|
|
88
88
|
control={
|
|
89
89
|
<Checkbox
|
|
90
90
|
checked={labelsAlignRight}
|
|
91
91
|
onChange={() => model.setLabelsAlignRight(!labelsAlignRight)}
|
|
92
92
|
/>
|
|
93
93
|
}
|
|
94
|
-
label="
|
|
94
|
+
label="Tree labels align right?"
|
|
95
95
|
/>
|
|
96
|
-
|
|
97
96
|
{!noTree ? (
|
|
98
97
|
<div>
|
|
99
|
-
<
|
|
98
|
+
<FormControlLabel2
|
|
100
99
|
control={
|
|
101
100
|
<Checkbox
|
|
102
101
|
checked={treeWidthMatchesArea}
|
|
@@ -108,7 +107,7 @@ const SettingsDialog = observer(function ({
|
|
|
108
107
|
label="Make tree width fit to tree area?"
|
|
109
108
|
/>
|
|
110
109
|
{!treeWidthMatchesArea ? (
|
|
111
|
-
<div
|
|
110
|
+
<div className={classes.flex}>
|
|
112
111
|
<Typography>Tree width ({treeWidth}px)</Typography>
|
|
113
112
|
<Slider
|
|
114
113
|
className={classes.field}
|
|
@@ -121,8 +120,21 @@ const SettingsDialog = observer(function ({
|
|
|
121
120
|
) : null}
|
|
122
121
|
</div>
|
|
123
122
|
) : null}
|
|
123
|
+
</div>
|
|
124
|
+
<div>
|
|
125
|
+
<h1>MSA options</h1>
|
|
126
|
+
|
|
127
|
+
<FormControlLabel2
|
|
128
|
+
control={
|
|
129
|
+
<Checkbox
|
|
130
|
+
checked={bgColor}
|
|
131
|
+
onChange={() => model.setBgColor(!bgColor)}
|
|
132
|
+
/>
|
|
133
|
+
}
|
|
134
|
+
label="Color background tiles of MSA?"
|
|
135
|
+
/>
|
|
124
136
|
|
|
125
|
-
<div
|
|
137
|
+
<div className={classes.flex}>
|
|
126
138
|
<Typography>Column width ({colWidth}px)</Typography>
|
|
127
139
|
<Slider
|
|
128
140
|
className={classes.field}
|
|
@@ -132,7 +144,7 @@ const SettingsDialog = observer(function ({
|
|
|
132
144
|
onChange={(_, val) => model.setColWidth(val as number)}
|
|
133
145
|
/>
|
|
134
146
|
</div>
|
|
135
|
-
<div
|
|
147
|
+
<div className={classes.flex}>
|
|
136
148
|
<Typography>Row height ({rowHeight}px)</Typography>
|
|
137
149
|
<Slider
|
|
138
150
|
className={classes.field}
|
|
@@ -155,19 +167,24 @@ const SettingsDialog = observer(function ({
|
|
|
155
167
|
</MenuItem>
|
|
156
168
|
))}
|
|
157
169
|
</TextField>
|
|
170
|
+
</div>
|
|
171
|
+
</>
|
|
172
|
+
)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const SettingsDialog = observer(function ({
|
|
176
|
+
model,
|
|
177
|
+
onClose,
|
|
178
|
+
}: {
|
|
179
|
+
model: MsaViewModel
|
|
180
|
+
onClose: () => void
|
|
181
|
+
}) {
|
|
182
|
+
return (
|
|
183
|
+
<Dialog open onClose={() => onClose()} title="Settings">
|
|
184
|
+
<DialogContent>
|
|
185
|
+
<SettingsContent model={model} />
|
|
158
186
|
<DialogActions>
|
|
159
|
-
<Button
|
|
160
|
-
onClick={() => {
|
|
161
|
-
model.setRowHeight(+rowHeight)
|
|
162
|
-
model.setColWidth(+colWidth)
|
|
163
|
-
if (!noTree) {
|
|
164
|
-
model.setTreeWidth(+treeWidth)
|
|
165
|
-
}
|
|
166
|
-
onClose()
|
|
167
|
-
}}
|
|
168
|
-
variant="contained"
|
|
169
|
-
color="primary"
|
|
170
|
-
>
|
|
187
|
+
<Button onClick={() => onClose()} variant="contained" color="primary">
|
|
171
188
|
Submit
|
|
172
189
|
</Button>
|
|
173
190
|
</DialogActions>
|