react-msaview 3.1.4 → 3.1.6
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 -40
- package/dist/DataModel.d.ts +34 -0
- package/dist/DataModel.js +46 -0
- package/dist/DataModel.js.map +1 -0
- package/dist/SelectedStructuresMixin.d.ts +46 -0
- package/dist/SelectedStructuresMixin.js +52 -0
- package/dist/SelectedStructuresMixin.js.map +1 -0
- package/dist/components/MSAPanel/MSABlock.js +32 -16
- package/dist/components/MSAPanel/MSABlock.js.map +1 -1
- package/dist/components/MSAPanel/renderMSABlock.js +1 -1
- package/dist/components/MSAPanel/renderMSABlock.js.map +1 -1
- package/dist/components/MSAPanel/renderMSAMouseover.js +14 -4
- package/dist/components/MSAPanel/renderMSAMouseover.js.map +1 -1
- package/dist/components/MSAView.js +2 -2
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/TreePanel/TreeNodeMenu.js +65 -55
- package/dist/components/TreePanel/TreeNodeMenu.js.map +1 -1
- package/dist/components/TreePanel/renderTreeCanvas.js +13 -12
- package/dist/components/TreePanel/renderTreeCanvas.js.map +1 -1
- package/dist/components/dialogs/SettingsDialog.js +42 -32
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/measureTextCanvas.d.ts +1 -1
- package/dist/measureTextCanvas.js +1 -1
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model.d.ts +121 -108
- package/dist/model.js +72 -94
- package/dist/model.js.map +1 -1
- package/dist/parsers/ClustalMSA.d.ts +1 -11
- package/dist/parsers/ClustalMSA.js +1 -15
- package/dist/parsers/ClustalMSA.js.map +1 -1
- package/dist/util.d.ts +0 -1
- package/dist/util.js +0 -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 -2
- package/src/DataModel.ts +46 -0
- package/src/SelectedStructuresMixin.ts +59 -0
- package/src/components/MSAPanel/MSABlock.tsx +33 -18
- package/src/components/MSAPanel/renderMSABlock.ts +0 -1
- package/src/components/MSAPanel/renderMSAMouseover.ts +16 -3
- package/src/components/MSAView.tsx +3 -3
- package/src/components/TreePanel/TreeNodeMenu.tsx +93 -84
- package/src/components/TreePanel/renderTreeCanvas.ts +19 -9
- package/src/components/dialogs/SettingsDialog.tsx +121 -117
- package/src/measureTextCanvas.ts +1 -1
- package/src/model.ts +88 -110
- package/src/parsers/ClustalMSA.ts +1 -15
- package/src/util.ts +0 -11
- package/src/version.ts +1 -1
|
@@ -35,142 +35,146 @@ function FormControlLabel2(rest: FormControlLabelProps) {
|
|
|
35
35
|
)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function Checkbox2({
|
|
39
|
+
checked,
|
|
40
|
+
label,
|
|
41
|
+
onChange,
|
|
42
|
+
}: {
|
|
43
|
+
checked: boolean
|
|
44
|
+
label: string
|
|
45
|
+
onChange: () => void
|
|
46
|
+
}) {
|
|
47
|
+
return (
|
|
48
|
+
<FormControlLabel2
|
|
49
|
+
control={<Checkbox checked={checked} onChange={onChange} />}
|
|
50
|
+
label={label}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
38
55
|
const SettingsContent = observer(function ({ model }: { model: MsaViewModel }) {
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<TreeSettings model={model} />
|
|
59
|
+
<MSASettings model={model} />
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
function TreeSettings({ model }: { model: MsaViewModel }) {
|
|
39
65
|
const { classes } = useStyles()
|
|
40
66
|
const {
|
|
41
|
-
bgColor,
|
|
42
|
-
colWidth,
|
|
43
|
-
colorSchemeName,
|
|
44
67
|
drawTree,
|
|
45
68
|
drawNodeBubbles,
|
|
46
69
|
labelsAlignRight,
|
|
47
70
|
noTree,
|
|
48
|
-
rowHeight,
|
|
49
71
|
showBranchLen,
|
|
50
72
|
treeWidthMatchesArea,
|
|
51
73
|
treeWidth,
|
|
52
74
|
} = model
|
|
75
|
+
|
|
53
76
|
return (
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
checked={showBranchLen}
|
|
62
|
-
onChange={() => model.setShowBranchLen(!showBranchLen)}
|
|
63
|
-
/>
|
|
64
|
-
}
|
|
65
|
-
label="Show branch length?"
|
|
66
|
-
/>
|
|
77
|
+
<div>
|
|
78
|
+
<h1>Tree options</h1>
|
|
79
|
+
<Checkbox2
|
|
80
|
+
checked={showBranchLen}
|
|
81
|
+
onChange={() => model.setShowBranchLen(!showBranchLen)}
|
|
82
|
+
label="Show branch length?"
|
|
83
|
+
/>
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
control={
|
|
79
|
-
<Checkbox
|
|
80
|
-
checked={drawTree}
|
|
81
|
-
onChange={() => model.setDrawTree(!drawTree)}
|
|
82
|
-
/>
|
|
83
|
-
}
|
|
84
|
-
label="Show tree?"
|
|
85
|
-
/>
|
|
85
|
+
<Checkbox2
|
|
86
|
+
checked={drawNodeBubbles}
|
|
87
|
+
onChange={() => model.setDrawNodeBubbles(!drawNodeBubbles)}
|
|
88
|
+
label="Draw clickable bubbles on tree branches?"
|
|
89
|
+
/>
|
|
90
|
+
<Checkbox2
|
|
91
|
+
checked={drawTree}
|
|
92
|
+
onChange={() => model.setDrawTree(!drawTree)}
|
|
93
|
+
label="Show tree?"
|
|
94
|
+
/>
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<Checkbox
|
|
101
|
-
checked={treeWidthMatchesArea}
|
|
102
|
-
onChange={() =>
|
|
103
|
-
model.setTreeWidthMatchesArea(!treeWidthMatchesArea)
|
|
104
|
-
}
|
|
105
|
-
/>
|
|
106
|
-
}
|
|
107
|
-
label="Make tree width fit to tree area?"
|
|
108
|
-
/>
|
|
109
|
-
{!treeWidthMatchesArea ? (
|
|
110
|
-
<div className={classes.flex}>
|
|
111
|
-
<Typography>Tree width ({treeWidth}px)</Typography>
|
|
112
|
-
<Slider
|
|
113
|
-
className={classes.field}
|
|
114
|
-
min={50}
|
|
115
|
-
max={600}
|
|
116
|
-
value={treeWidth}
|
|
117
|
-
onChange={(_, val) => model.setTreeWidth(val as number)}
|
|
118
|
-
/>
|
|
119
|
-
</div>
|
|
120
|
-
) : null}
|
|
121
|
-
</div>
|
|
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
|
-
/>
|
|
136
|
-
|
|
137
|
-
<div className={classes.flex}>
|
|
138
|
-
<Typography>Column width ({colWidth}px)</Typography>
|
|
139
|
-
<Slider
|
|
140
|
-
className={classes.field}
|
|
141
|
-
min={1}
|
|
142
|
-
max={50}
|
|
143
|
-
value={colWidth}
|
|
144
|
-
onChange={(_, val) => model.setColWidth(val as number)}
|
|
145
|
-
/>
|
|
146
|
-
</div>
|
|
147
|
-
<div className={classes.flex}>
|
|
148
|
-
<Typography>Row height ({rowHeight}px)</Typography>
|
|
149
|
-
<Slider
|
|
150
|
-
className={classes.field}
|
|
151
|
-
min={1}
|
|
152
|
-
max={50}
|
|
153
|
-
value={rowHeight}
|
|
154
|
-
onChange={(_, val) => model.setRowHeight(val as number)}
|
|
96
|
+
<Checkbox2
|
|
97
|
+
checked={labelsAlignRight}
|
|
98
|
+
onChange={() => model.setLabelsAlignRight(!labelsAlignRight)}
|
|
99
|
+
label="Tree labels align right?"
|
|
100
|
+
/>
|
|
101
|
+
{!noTree ? (
|
|
102
|
+
<div>
|
|
103
|
+
<Checkbox2
|
|
104
|
+
checked={treeWidthMatchesArea}
|
|
105
|
+
onChange={() =>
|
|
106
|
+
model.setTreeWidthMatchesArea(!treeWidthMatchesArea)
|
|
107
|
+
}
|
|
108
|
+
label="Make tree width fit to tree area?"
|
|
155
109
|
/>
|
|
110
|
+
{!treeWidthMatchesArea ? (
|
|
111
|
+
<div className={classes.flex}>
|
|
112
|
+
<Typography>Tree width ({treeWidth}px)</Typography>
|
|
113
|
+
<Slider
|
|
114
|
+
className={classes.field}
|
|
115
|
+
min={50}
|
|
116
|
+
max={600}
|
|
117
|
+
value={treeWidth}
|
|
118
|
+
onChange={(_, val) => model.setTreeWidth(val as number)}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
) : null}
|
|
156
122
|
</div>
|
|
123
|
+
) : null}
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function MSASettings({ model }: { model: MsaViewModel }) {
|
|
129
|
+
const { classes } = useStyles()
|
|
130
|
+
const { bgColor, colWidth, colorSchemeName, rowHeight } = model
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<div>
|
|
134
|
+
<h1>MSA options</h1>
|
|
135
|
+
|
|
136
|
+
<Checkbox2
|
|
137
|
+
checked={bgColor}
|
|
138
|
+
onChange={() => model.setBgColor(!bgColor)}
|
|
139
|
+
label="Color background tiles of MSA?"
|
|
140
|
+
/>
|
|
157
141
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
</MenuItem>
|
|
168
|
-
))}
|
|
169
|
-
</TextField>
|
|
142
|
+
<div className={classes.flex}>
|
|
143
|
+
<Typography>Column width ({colWidth}px)</Typography>
|
|
144
|
+
<Slider
|
|
145
|
+
className={classes.field}
|
|
146
|
+
min={1}
|
|
147
|
+
max={50}
|
|
148
|
+
value={colWidth}
|
|
149
|
+
onChange={(_, val) => model.setColWidth(val as number)}
|
|
150
|
+
/>
|
|
170
151
|
</div>
|
|
171
|
-
|
|
152
|
+
<div className={classes.flex}>
|
|
153
|
+
<Typography>Row height ({rowHeight}px)</Typography>
|
|
154
|
+
<Slider
|
|
155
|
+
className={classes.field}
|
|
156
|
+
min={1}
|
|
157
|
+
max={50}
|
|
158
|
+
value={rowHeight}
|
|
159
|
+
onChange={(_, val) => model.setRowHeight(val as number)}
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<TextField
|
|
164
|
+
select
|
|
165
|
+
label="Color scheme"
|
|
166
|
+
value={colorSchemeName}
|
|
167
|
+
onChange={event => model.setColorSchemeName(event.target.value)}
|
|
168
|
+
>
|
|
169
|
+
{Object.keys(colorSchemes).map(option => (
|
|
170
|
+
<MenuItem key={option} value={option}>
|
|
171
|
+
{option}
|
|
172
|
+
</MenuItem>
|
|
173
|
+
))}
|
|
174
|
+
</TextField>
|
|
175
|
+
</div>
|
|
172
176
|
)
|
|
173
|
-
}
|
|
177
|
+
}
|
|
174
178
|
|
|
175
179
|
const SettingsDialog = observer(function ({
|
|
176
180
|
model,
|
package/src/measureTextCanvas.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
let canvasHandle: HTMLCanvasElement | undefined
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export function measureTextCanvas(text: string, fontSize: number) {
|
|
4
4
|
if (!canvasHandle) {
|
|
5
5
|
canvasHandle = document.createElement('canvas')
|
|
6
6
|
}
|
package/src/model.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { autorun } from 'mobx'
|
|
3
|
-
import { Instance, cast, types, addDisposer
|
|
3
|
+
import { Instance, cast, types, addDisposer } from 'mobx-state-tree'
|
|
4
4
|
import { hierarchy, cluster, HierarchyNode } from 'd3-hierarchy'
|
|
5
5
|
import { ascending } from 'd3-array'
|
|
6
6
|
import Stockholm from 'stockholm-js'
|
|
7
7
|
import { saveAs } from 'file-saver'
|
|
8
|
+
import { Theme } from '@mui/material'
|
|
9
|
+
|
|
8
10
|
// jbrowse
|
|
9
11
|
import { FileLocation, ElementId } from '@jbrowse/core/util/types/mst'
|
|
10
12
|
import { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
|
|
@@ -16,7 +18,6 @@ import BaseViewModel from '@jbrowse/core/pluggableElementTypes/models/BaseViewMo
|
|
|
16
18
|
import {
|
|
17
19
|
clamp,
|
|
18
20
|
collapse,
|
|
19
|
-
filterHiddenLeafNodes,
|
|
20
21
|
generateNodeIds,
|
|
21
22
|
maxLength,
|
|
22
23
|
setBrLength,
|
|
@@ -24,20 +25,26 @@ import {
|
|
|
24
25
|
NodeWithIds,
|
|
25
26
|
NodeWithIdsAndLength,
|
|
26
27
|
} from './util'
|
|
28
|
+
|
|
29
|
+
import { blocksX, blocksY } from './calculateBlocks'
|
|
30
|
+
import { measureTextCanvas } from './measureTextCanvas'
|
|
31
|
+
|
|
32
|
+
// components
|
|
27
33
|
import TextTrack from './components/TextTrack'
|
|
28
34
|
import BoxTrack from './components/BoxTrack'
|
|
35
|
+
|
|
36
|
+
// parsers
|
|
29
37
|
import ClustalMSA from './parsers/ClustalMSA'
|
|
30
38
|
import StockholmMSA from './parsers/StockholmMSA'
|
|
31
39
|
import FastaMSA from './parsers/FastaMSA'
|
|
32
40
|
import parseNewick from './parseNewick'
|
|
33
41
|
import colorSchemes from './colorSchemes'
|
|
42
|
+
|
|
43
|
+
// models
|
|
34
44
|
import { UniprotTrack } from './UniprotTrack'
|
|
35
|
-
import {
|
|
45
|
+
import { DataModelF } from './DataModel'
|
|
36
46
|
import { DialogQueueSessionMixin } from './DialogQueue'
|
|
37
|
-
import {
|
|
38
|
-
import { Theme } from '@mui/material'
|
|
39
|
-
import { blocksX, blocksY } from './calculateBlocks'
|
|
40
|
-
import measureTextCanvas from './measureTextCanvas'
|
|
47
|
+
import { SelectedStructuresMixin } from './SelectedStructuresMixin'
|
|
41
48
|
|
|
42
49
|
export interface RowDetails {
|
|
43
50
|
[key: string]: unknown
|
|
@@ -82,16 +89,30 @@ export interface IBoxTrack {
|
|
|
82
89
|
|
|
83
90
|
export type BasicTrack = IBoxTrack | ITextTrack
|
|
84
91
|
|
|
85
|
-
export type StructureSnap = SnapshotIn<typeof StructureModel>
|
|
86
|
-
|
|
87
92
|
/**
|
|
88
93
|
* #stateModel MsaView
|
|
89
94
|
* extends
|
|
90
95
|
* - BaseViewModel
|
|
91
96
|
* - DialogQueueSessionMixin
|
|
97
|
+
* - SelectedStructuresMixin
|
|
92
98
|
*/
|
|
93
99
|
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
94
100
|
|
|
101
|
+
function reparseTree(tree: NodeWithIds): NodeWithIds {
|
|
102
|
+
return {
|
|
103
|
+
...tree,
|
|
104
|
+
branchset: tree.branchset.map(r =>
|
|
105
|
+
r.branchset.length
|
|
106
|
+
? reparseTree(r)
|
|
107
|
+
: {
|
|
108
|
+
branchset: [r],
|
|
109
|
+
id: `${r.id}-leafnode`,
|
|
110
|
+
name: `${r.name}-hidden`,
|
|
111
|
+
},
|
|
112
|
+
),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
95
116
|
export type DialogComponentType =
|
|
96
117
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
118
|
| React.LazyExoticComponent<React.FC<any>>
|
|
@@ -102,6 +123,7 @@ const model = types
|
|
|
102
123
|
.compose(
|
|
103
124
|
BaseViewModel,
|
|
104
125
|
DialogQueueSessionMixin(),
|
|
126
|
+
SelectedStructuresMixin(),
|
|
105
127
|
types.model('MsaView', {
|
|
106
128
|
/**
|
|
107
129
|
* #property
|
|
@@ -157,12 +179,6 @@ const model = types
|
|
|
157
179
|
*/
|
|
158
180
|
scrollX: 0,
|
|
159
181
|
|
|
160
|
-
/**
|
|
161
|
-
* #property
|
|
162
|
-
* currently "selected" structures, generally PDB 3-D protein structures
|
|
163
|
-
*/
|
|
164
|
-
selectedStructures: types.array(StructureModel),
|
|
165
|
-
|
|
166
182
|
/**
|
|
167
183
|
* #property
|
|
168
184
|
* right-align the labels
|
|
@@ -244,12 +260,7 @@ const model = types
|
|
|
244
260
|
*/
|
|
245
261
|
collapsed: types.array(types.string),
|
|
246
262
|
|
|
247
|
-
|
|
248
|
-
* #property
|
|
249
|
-
* array of leaf nodes that are 'hidden', similar to collapsed but for leaf nodes
|
|
250
|
-
*/
|
|
251
|
-
hidden: types.array(types.string),
|
|
252
|
-
|
|
263
|
+
collapsed2: types.array(types.string),
|
|
253
264
|
/**
|
|
254
265
|
* #property
|
|
255
266
|
* focus on particular subtree
|
|
@@ -274,26 +285,7 @@ const model = types
|
|
|
274
285
|
* data from the loaded tree/msa/treeMetadata, generally loaded by
|
|
275
286
|
* autorun
|
|
276
287
|
*/
|
|
277
|
-
data: types.optional(
|
|
278
|
-
types
|
|
279
|
-
.model({
|
|
280
|
-
tree: types.maybe(types.string),
|
|
281
|
-
msa: types.maybe(types.string),
|
|
282
|
-
treeMetadata: types.maybe(types.string),
|
|
283
|
-
})
|
|
284
|
-
.actions(self => ({
|
|
285
|
-
setTree(tree?: string) {
|
|
286
|
-
self.tree = tree
|
|
287
|
-
},
|
|
288
|
-
setMSA(msa?: string) {
|
|
289
|
-
self.msa = msa
|
|
290
|
-
},
|
|
291
|
-
setTreeMetadata(treeMetadata?: string) {
|
|
292
|
-
self.treeMetadata = treeMetadata
|
|
293
|
-
},
|
|
294
|
-
})),
|
|
295
|
-
{ tree: '', msa: '' },
|
|
296
|
-
),
|
|
288
|
+
data: types.optional(DataModelF(), { tree: '', msa: '' }),
|
|
297
289
|
}),
|
|
298
290
|
)
|
|
299
291
|
.volatile(() => ({
|
|
@@ -321,6 +313,18 @@ const model = types
|
|
|
321
313
|
*/
|
|
322
314
|
mouseCol: undefined as number | undefined,
|
|
323
315
|
|
|
316
|
+
/**
|
|
317
|
+
* #volatile
|
|
318
|
+
* the currently mouse-click row
|
|
319
|
+
*/
|
|
320
|
+
mouseClickRow: undefined as number | undefined,
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* #volatile
|
|
324
|
+
* the currently mouse-click column
|
|
325
|
+
*/
|
|
326
|
+
mouseClickCol: undefined as number | undefined,
|
|
327
|
+
|
|
324
328
|
/**
|
|
325
329
|
* #volatile
|
|
326
330
|
* a dummy variable that is incremented when ref changes so autorun for
|
|
@@ -333,6 +337,11 @@ const model = types
|
|
|
333
337
|
*/
|
|
334
338
|
minimapHeight: 56,
|
|
335
339
|
|
|
340
|
+
/**
|
|
341
|
+
* #volatile
|
|
342
|
+
*/
|
|
343
|
+
marginLeft: 20,
|
|
344
|
+
|
|
336
345
|
/**
|
|
337
346
|
* #volatile
|
|
338
347
|
*/
|
|
@@ -352,49 +361,6 @@ const model = types
|
|
|
352
361
|
self.height = height
|
|
353
362
|
},
|
|
354
363
|
|
|
355
|
-
/**
|
|
356
|
-
* #action
|
|
357
|
-
* add to the selected structures
|
|
358
|
-
*/
|
|
359
|
-
addStructureToSelection(elt: StructureSnap) {
|
|
360
|
-
self.selectedStructures.push(elt)
|
|
361
|
-
},
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* #action
|
|
365
|
-
* remove from the selected structures
|
|
366
|
-
*/
|
|
367
|
-
removeStructureFromSelection(elt: StructureSnap) {
|
|
368
|
-
const r = self.selectedStructures.find(node => node.id === elt.id)
|
|
369
|
-
if (r) {
|
|
370
|
-
self.selectedStructures.remove(r)
|
|
371
|
-
}
|
|
372
|
-
},
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* #action
|
|
376
|
-
* toggle a structure from the selected structures list
|
|
377
|
-
*/
|
|
378
|
-
toggleStructureSelection(elt: {
|
|
379
|
-
id: string
|
|
380
|
-
structure: { startPos: number; endPos: number; pdb: string }
|
|
381
|
-
}) {
|
|
382
|
-
const r = self.selectedStructures.find(node => node.id === elt.id)
|
|
383
|
-
if (r) {
|
|
384
|
-
self.selectedStructures.remove(r)
|
|
385
|
-
} else {
|
|
386
|
-
self.selectedStructures.push(elt)
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* #action
|
|
392
|
-
* clear all selected structures
|
|
393
|
-
*/
|
|
394
|
-
clearSelectedStructures() {
|
|
395
|
-
self.selectedStructures = cast([])
|
|
396
|
-
},
|
|
397
|
-
|
|
398
364
|
/**
|
|
399
365
|
* #action
|
|
400
366
|
* set error state
|
|
@@ -412,6 +378,15 @@ const model = types
|
|
|
412
378
|
self.mouseRow = row
|
|
413
379
|
},
|
|
414
380
|
|
|
381
|
+
/**
|
|
382
|
+
* #action
|
|
383
|
+
* set mouse click position (row, column) in the MSA
|
|
384
|
+
*/
|
|
385
|
+
setMouseClickPos(col?: number, row?: number) {
|
|
386
|
+
self.mouseClickCol = col
|
|
387
|
+
self.mouseClickRow = row
|
|
388
|
+
},
|
|
389
|
+
|
|
415
390
|
/**
|
|
416
391
|
* #action
|
|
417
392
|
* set row height (px)
|
|
@@ -488,20 +463,6 @@ const model = types
|
|
|
488
463
|
self.drawTree = arg
|
|
489
464
|
},
|
|
490
465
|
|
|
491
|
-
/**
|
|
492
|
-
* #action
|
|
493
|
-
*/
|
|
494
|
-
hideNode(arg: string) {
|
|
495
|
-
self.hidden.push(arg)
|
|
496
|
-
},
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* #action
|
|
500
|
-
*/
|
|
501
|
-
clearHidden() {
|
|
502
|
-
self.hidden.clear()
|
|
503
|
-
},
|
|
504
|
-
|
|
505
466
|
/**
|
|
506
467
|
* #action
|
|
507
468
|
*/
|
|
@@ -513,6 +474,16 @@ const model = types
|
|
|
513
474
|
}
|
|
514
475
|
},
|
|
515
476
|
|
|
477
|
+
/**
|
|
478
|
+
* #action
|
|
479
|
+
*/
|
|
480
|
+
toggleCollapsed2(node: string) {
|
|
481
|
+
if (self.collapsed2.includes(node)) {
|
|
482
|
+
self.collapsed2.remove(node)
|
|
483
|
+
} else {
|
|
484
|
+
self.collapsed2.push(node)
|
|
485
|
+
}
|
|
486
|
+
},
|
|
516
487
|
/**
|
|
517
488
|
* #action
|
|
518
489
|
*/
|
|
@@ -675,7 +646,7 @@ const model = types
|
|
|
675
646
|
* #getter
|
|
676
647
|
*/
|
|
677
648
|
get _tree(): NodeWithIds {
|
|
678
|
-
|
|
649
|
+
const ret = self.data.tree
|
|
679
650
|
? generateNodeIds(parseNewick(self.data.tree))
|
|
680
651
|
: this.MSA?.getTree() || {
|
|
681
652
|
noTree: true,
|
|
@@ -683,6 +654,7 @@ const model = types
|
|
|
683
654
|
id: 'empty',
|
|
684
655
|
name: 'empty',
|
|
685
656
|
}
|
|
657
|
+
return reparseTree(ret)
|
|
686
658
|
},
|
|
687
659
|
/**
|
|
688
660
|
* #getter
|
|
@@ -721,18 +693,13 @@ const model = types
|
|
|
721
693
|
}
|
|
722
694
|
}
|
|
723
695
|
|
|
724
|
-
if (self.collapsed.length) {
|
|
725
|
-
self.collapsed
|
|
696
|
+
if (self.collapsed.length || self.collapsed2.length) {
|
|
697
|
+
;[...self.collapsed, ...self.collapsed2]
|
|
726
698
|
.map(collapsedId => hier.find(node => node.data.id === collapsedId))
|
|
727
699
|
.filter(notEmpty)
|
|
728
700
|
.map(node => collapse(node))
|
|
729
701
|
}
|
|
730
|
-
|
|
731
|
-
self.hidden
|
|
732
|
-
.map(hiddenId => hier.find(node => node.data.id === hiddenId))
|
|
733
|
-
.filter(notEmpty)
|
|
734
|
-
.map(node => filterHiddenLeafNodes(node.parent, node.id))
|
|
735
|
-
}
|
|
702
|
+
|
|
736
703
|
return hier
|
|
737
704
|
},
|
|
738
705
|
/**
|
|
@@ -758,6 +725,13 @@ const model = types
|
|
|
758
725
|
get msaAreaWidth() {
|
|
759
726
|
return self.width - self.treeAreaWidth
|
|
760
727
|
},
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* #getter
|
|
731
|
+
*/
|
|
732
|
+
get treeAreaWidthMinusMargin() {
|
|
733
|
+
return self.treeAreaWidth - self.marginLeft
|
|
734
|
+
},
|
|
761
735
|
/**
|
|
762
736
|
* #getter
|
|
763
737
|
*/
|
|
@@ -1148,7 +1122,7 @@ const model = types
|
|
|
1148
1122
|
relativePxToBp(rowName: string, position: number) {
|
|
1149
1123
|
const { rowNames, rows } = self
|
|
1150
1124
|
const index = rowNames.indexOf(rowName)
|
|
1151
|
-
if (index !== -1) {
|
|
1125
|
+
if (index !== -1 && rows[index]) {
|
|
1152
1126
|
const row = rows[index][1]
|
|
1153
1127
|
|
|
1154
1128
|
let k = 0
|
|
@@ -1170,7 +1144,7 @@ const model = types
|
|
|
1170
1144
|
relativePxToBp2(rowName: string, position: number) {
|
|
1171
1145
|
const { rowNames, rows } = self
|
|
1172
1146
|
const index = rowNames.indexOf(rowName)
|
|
1173
|
-
if (index !== -1) {
|
|
1147
|
+
if (index !== -1 && rows[index]) {
|
|
1174
1148
|
const row = rows[index][1]
|
|
1175
1149
|
|
|
1176
1150
|
let k = 0
|
|
@@ -1219,6 +1193,7 @@ const model = types
|
|
|
1219
1193
|
includeMinimap?: boolean
|
|
1220
1194
|
exportType: string
|
|
1221
1195
|
}) {
|
|
1196
|
+
const { renderToSvg } = await import('./renderToSvg')
|
|
1222
1197
|
const html = await renderToSvg(self as MsaViewModel, opts)
|
|
1223
1198
|
const blob = new Blob([html], { type: 'image/svg+xml' })
|
|
1224
1199
|
saveAs(blob, 'image.svg')
|
|
@@ -1286,7 +1261,10 @@ const model = types
|
|
|
1286
1261
|
autorun(async () => {
|
|
1287
1262
|
if (self.treeWidthMatchesArea) {
|
|
1288
1263
|
self.setTreeWidth(
|
|
1289
|
-
Math.max(
|
|
1264
|
+
Math.max(
|
|
1265
|
+
50,
|
|
1266
|
+
self.treeAreaWidth - self.labelsWidth - 10 - self.marginLeft,
|
|
1267
|
+
),
|
|
1290
1268
|
)
|
|
1291
1269
|
}
|
|
1292
1270
|
}),
|
|
@@ -60,20 +60,6 @@ export default class ClustalMSA {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
get tracks() {
|
|
63
|
-
return
|
|
64
|
-
? [
|
|
65
|
-
{
|
|
66
|
-
id: 'seqConsensus',
|
|
67
|
-
name: 'Sequence consensus',
|
|
68
|
-
data: this.seqConsensus,
|
|
69
|
-
customColorScheme: {
|
|
70
|
-
'*': 'white',
|
|
71
|
-
':': 'grey',
|
|
72
|
-
'.': 'darkgrey',
|
|
73
|
-
' ': 'black',
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
]
|
|
77
|
-
: []
|
|
63
|
+
return []
|
|
78
64
|
}
|
|
79
65
|
}
|
package/src/util.ts
CHANGED
|
@@ -145,17 +145,6 @@ export function collapse(d: HierarchyNode<NodeWithIds>) {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
// Collapse the node and all it's children, from
|
|
149
|
-
// https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd
|
|
150
|
-
export function filterHiddenLeafNodes(
|
|
151
|
-
d: HierarchyNode<NodeWithIds> | null,
|
|
152
|
-
hiddenId?: string,
|
|
153
|
-
) {
|
|
154
|
-
if (d?.children) {
|
|
155
|
-
d.children = d.children.filter(f => f.id !== hiddenId)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
148
|
export function clamp(min: number, num: number, max: number) {
|
|
160
149
|
return Math.min(Math.max(num, min), max)
|
|
161
150
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '3.1.
|
|
1
|
+
export const version = '3.1.6'
|