react-msaview 3.1.11 → 3.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 +32 -31
- package/dist/colorSchemes.d.ts +2 -2
- package/dist/colorSchemes.js +3 -4
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/Loading.d.ts +1 -1
- package/dist/components/Loading.js +4 -4
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.d.ts +1 -1
- package/dist/components/MSAView.js +13 -9
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +1 -1
- package/dist/components/ResizeHandles.js +2 -2
- package/dist/components/SequenceTextArea.js +4 -0
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/TextTrack.d.ts +1 -1
- package/dist/components/Track.d.ts +1 -1
- package/dist/components/VerticalScrollbar.d.ts +6 -0
- package/dist/components/VerticalScrollbar.js +65 -0
- package/dist/components/VerticalScrollbar.js.map +1 -0
- package/dist/components/dialogs/AddTrackDialog.d.ts +1 -1
- package/dist/components/dialogs/DomainDialog.d.ts +6 -0
- package/dist/components/dialogs/DomainDialog.js +19 -0
- package/dist/components/dialogs/DomainDialog.js.map +1 -0
- package/dist/components/dialogs/ExportSVGDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.d.ts +4 -4
- package/dist/components/dialogs/InterProScanDialog.js +37 -8
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/dialogs/MetadataDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.js +10 -1
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/components/dialogs/TabPanel.d.ts +6 -0
- package/dist/components/dialogs/TabPanel.js +6 -0
- package/dist/components/dialogs/TabPanel.js.map +1 -0
- package/dist/components/dialogs/TracklistDialog.d.ts +1 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.d.ts +7 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js +58 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -0
- package/dist/components/header/Header.d.ts +1 -1
- package/dist/components/header/Header.js +8 -5
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderInfoArea.d.ts +1 -1
- package/dist/components/header/HeaderMenu.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.js +54 -41
- package/dist/components/header/HeaderMenuExtra.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.d.ts +1 -1
- package/dist/components/header/HeaderStatusArea.js +2 -1
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/MultiAlignmentSelector.d.ts +1 -1
- package/dist/components/header/ZoomControls.js +31 -1
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/import/ImportForm.d.ts +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.d.ts +1 -1
- package/dist/components/import/ImportFormExamples.js +10 -8
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.d.ts +2 -2
- package/dist/components/minimap/Minimap.d.ts +1 -1
- package/dist/components/minimap/Minimap.js +14 -15
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.d.ts +1 -1
- package/dist/components/minimap/MinimapSVG.js +1 -1
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/msa/MSACanvas.d.ts +1 -1
- package/dist/components/msa/MSACanvas.js +3 -3
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.d.ts +3 -3
- package/dist/components/msa/MSACanvasBlock.js +4 -3
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.d.ts +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/MSAPanel.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +2 -3
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +2 -2
- package/dist/components/msa/renderMSABlock.js +12 -12
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.d.ts +1 -1
- package/dist/components/tree/TreeBranchMenu.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.js +13 -12
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.d.ts +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -1
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeNodeMenu.d.ts +1 -1
- package/dist/components/tree/TreeNodeMenu.js +2 -2
- package/dist/components/tree/TreeNodeMenu.js.map +1 -1
- package/dist/components/tree/TreePanel.d.ts +1 -1
- package/dist/components/tree/TreeRuler.d.ts +1 -1
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +3 -3
- package/dist/components/tree/renderTreeCanvas.js +25 -9
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/util.js +1 -1
- package/dist/components/util.js.map +1 -1
- package/dist/fetchUtils.d.ts +1 -1
- package/dist/fetchUtils.js.map +1 -1
- package/dist/launchInterProScan.d.ts +9 -3
- package/dist/launchInterProScan.js +57 -22
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/model/DataModel.d.ts +5 -1
- package/dist/model/DataModel.js +10 -1
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/DialogQueue.d.ts +1 -1
- package/dist/model.d.ts +138 -43
- package/dist/model.js +235 -110
- package/dist/model.js.map +1 -1
- package/dist/parseNewick.js +1 -1
- package/dist/parseNewick.js.map +1 -1
- package/dist/parsers/ClustalMSA.d.ts +1 -1
- package/dist/parsers/FastaMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.js.map +1 -1
- package/dist/renderToSvg.d.ts +2 -2
- package/dist/renderToSvg.js +3 -28
- package/dist/renderToSvg.js.map +1 -1
- package/dist/reparseTree.d.ts +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.js +0 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +5 -2
- package/src/colorSchemes.ts +3 -2
- package/src/components/Checkbox2.tsx +1 -1
- package/src/components/Loading.tsx +11 -5
- package/src/components/MSAView.tsx +27 -18
- package/src/components/ResizeHandles.tsx +3 -3
- package/src/components/SequenceTextArea.tsx +8 -0
- package/src/components/TextTrack.tsx +1 -1
- package/src/components/Track.tsx +1 -1
- package/src/components/VerticalScrollbar.tsx +85 -0
- package/src/components/dialogs/AddTrackDialog.tsx +2 -2
- package/src/components/dialogs/DomainDialog.tsx +38 -0
- package/src/components/dialogs/ExportSVGDialog.tsx +1 -1
- package/src/components/dialogs/FeatureDialog.tsx +3 -3
- package/src/components/dialogs/InterProScanDialog.tsx +49 -11
- package/src/components/dialogs/MetadataDialog.tsx +1 -1
- package/src/components/dialogs/SettingsDialog.tsx +38 -3
- package/src/components/dialogs/TabPanel.tsx +19 -0
- package/src/components/dialogs/TracklistDialog.tsx +1 -1
- package/src/components/dialogs/UserProvidedDomainsDialog.tsx +133 -0
- package/src/components/header/Header.tsx +9 -6
- package/src/components/header/HeaderInfoArea.tsx +1 -1
- package/src/components/header/HeaderMenu.tsx +1 -1
- package/src/components/header/HeaderMenuExtra.tsx +65 -48
- package/src/components/header/HeaderStatusArea.tsx +3 -2
- package/src/components/header/MultiAlignmentSelector.tsx +1 -1
- package/src/components/header/ZoomControls.tsx +34 -0
- package/src/components/import/ImportForm.tsx +3 -3
- package/src/components/import/ImportFormExamples.tsx +19 -17
- package/src/components/import/util.ts +2 -2
- package/src/components/minimap/Minimap.tsx +15 -22
- package/src/components/minimap/MinimapSVG.tsx +2 -2
- package/src/components/msa/MSACanvas.tsx +11 -4
- package/src/components/msa/MSACanvasBlock.tsx +5 -4
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -6
- package/src/components/msa/MSAPanel.tsx +1 -1
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +5 -6
- package/src/components/msa/renderMSABlock.ts +37 -17
- package/src/components/msa/renderMSAMouseover.ts +1 -1
- package/src/components/tree/TreeBranchMenu.tsx +1 -1
- package/src/components/tree/TreeCanvas.tsx +15 -16
- package/src/components/tree/TreeCanvasBlock.tsx +3 -2
- package/src/components/tree/TreeNodeMenu.tsx +3 -3
- package/src/components/tree/TreePanel.tsx +1 -1
- package/src/components/tree/TreeRuler.tsx +1 -1
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +1 -1
- package/src/components/tree/renderTreeCanvas.ts +32 -12
- package/src/components/util.ts +1 -1
- package/src/fetchUtils.ts +2 -2
- package/src/launchInterProScan.ts +69 -24
- package/src/model/DataModel.ts +10 -0
- package/src/model/DialogQueue.ts +1 -1
- package/src/model.ts +262 -143
- package/src/parseNewick.ts +1 -1
- package/src/parsers/ClustalMSA.ts +1 -1
- package/src/parsers/FastaMSA.ts +1 -1
- package/src/parsers/StockholmMSA.ts +1 -1
- package/src/renderToSvg.tsx +6 -30
- package/src/reparseTree.ts +1 -1
- package/src/util.ts +2 -4
- package/src/version.ts +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { HierarchyNode } from 'd3-hierarchy'
|
|
2
|
-
import { Theme } from '@mui/material'
|
|
1
|
+
import type { HierarchyNode } from 'd3-hierarchy'
|
|
2
|
+
import type { Theme } from '@mui/material'
|
|
3
3
|
|
|
4
4
|
// locals
|
|
5
|
-
import { MsaViewModel } from '../../model'
|
|
5
|
+
import type { MsaViewModel } from '../../model'
|
|
6
6
|
import { getClustalXColor, getPercentIdentityColor } from '../../colorSchemes'
|
|
7
|
-
import { NodeWithIdsAndLength } from '../../util'
|
|
7
|
+
import type { NodeWithIdsAndLength } from '../../util'
|
|
8
8
|
|
|
9
9
|
export function renderMSABlock({
|
|
10
10
|
model,
|
|
@@ -28,13 +28,13 @@ export function renderMSABlock({
|
|
|
28
28
|
blockSizeYOverride?: number
|
|
29
29
|
}) {
|
|
30
30
|
const {
|
|
31
|
-
hierarchy,
|
|
32
31
|
colWidth,
|
|
33
32
|
blockSize,
|
|
34
33
|
rowHeight,
|
|
35
34
|
fontSize,
|
|
36
35
|
highResScaleFactor,
|
|
37
|
-
|
|
36
|
+
actuallyShowDomains,
|
|
37
|
+
leaves,
|
|
38
38
|
} = model
|
|
39
39
|
const k = highResScaleFactorOverride || highResScaleFactor
|
|
40
40
|
const bx = blockSizeXOverride || blockSize
|
|
@@ -45,15 +45,13 @@ export function renderMSABlock({
|
|
|
45
45
|
ctx.textAlign = 'center'
|
|
46
46
|
ctx.font = ctx.font.replace(/\d+px/, `${fontSize}px`)
|
|
47
47
|
|
|
48
|
-
const leaves = hierarchy.leaves()
|
|
49
|
-
|
|
50
48
|
const yStart = Math.max(0, Math.floor((offsetY - rowHeight) / rowHeight))
|
|
51
49
|
const yEnd = Math.max(0, Math.ceil((offsetY + by + rowHeight) / rowHeight))
|
|
52
50
|
const xStart = Math.max(0, Math.floor(offsetX / colWidth))
|
|
53
51
|
const xEnd = Math.max(0, Math.ceil((offsetX + bx) / colWidth))
|
|
54
52
|
const visibleLeaves = leaves.slice(yStart, yEnd)
|
|
55
53
|
|
|
56
|
-
if (!
|
|
54
|
+
if (!actuallyShowDomains) {
|
|
57
55
|
drawTiles({
|
|
58
56
|
model,
|
|
59
57
|
ctx,
|
|
@@ -101,6 +99,7 @@ function drawTiles({
|
|
|
101
99
|
colorSchemeName,
|
|
102
100
|
colorScheme,
|
|
103
101
|
colStats,
|
|
102
|
+
colStatsSums,
|
|
104
103
|
columns,
|
|
105
104
|
colWidth,
|
|
106
105
|
rowHeight,
|
|
@@ -116,19 +115,30 @@ function drawTiles({
|
|
|
116
115
|
const letter = str[i]
|
|
117
116
|
const color =
|
|
118
117
|
colorSchemeName === 'clustalx_protein_dynamic'
|
|
119
|
-
? getClustalXColor(
|
|
118
|
+
? getClustalXColor(
|
|
119
|
+
colStats[xStart + i],
|
|
120
|
+
colStatsSums[xStart + i],
|
|
121
|
+
model,
|
|
122
|
+
name,
|
|
123
|
+
xStart + i,
|
|
124
|
+
)
|
|
120
125
|
: colorSchemeName === 'percent_identity_dynamic'
|
|
121
126
|
? getPercentIdentityColor(
|
|
122
127
|
colStats[xStart + i],
|
|
128
|
+
colStatsSums[xStart + i],
|
|
123
129
|
model,
|
|
124
130
|
name,
|
|
125
131
|
xStart + i,
|
|
126
132
|
)
|
|
127
133
|
: colorScheme[letter.toUpperCase()]
|
|
128
134
|
if (bgColor) {
|
|
129
|
-
const x = i * colWidth + offsetX - (offsetX % colWidth)
|
|
130
135
|
ctx.fillStyle = color || theme.palette.background.default
|
|
131
|
-
ctx.fillRect(
|
|
136
|
+
ctx.fillRect(
|
|
137
|
+
i * colWidth + offsetX - (offsetX % colWidth),
|
|
138
|
+
y - rowHeight,
|
|
139
|
+
colWidth,
|
|
140
|
+
rowHeight,
|
|
141
|
+
)
|
|
132
142
|
}
|
|
133
143
|
}
|
|
134
144
|
}
|
|
@@ -152,9 +162,17 @@ function drawText({
|
|
|
152
162
|
xStart: number
|
|
153
163
|
xEnd: number
|
|
154
164
|
}) {
|
|
155
|
-
const {
|
|
156
|
-
|
|
157
|
-
|
|
165
|
+
const {
|
|
166
|
+
bgColor,
|
|
167
|
+
actuallyShowDomains,
|
|
168
|
+
showMsaLetters,
|
|
169
|
+
colorScheme,
|
|
170
|
+
columns,
|
|
171
|
+
colWidth,
|
|
172
|
+
contrastLettering,
|
|
173
|
+
rowHeight,
|
|
174
|
+
} = model
|
|
175
|
+
if (showMsaLetters) {
|
|
158
176
|
for (const node of visibleLeaves) {
|
|
159
177
|
const {
|
|
160
178
|
data: { name },
|
|
@@ -164,11 +182,13 @@ function drawText({
|
|
|
164
182
|
for (let i = 0; i < str?.length; i++) {
|
|
165
183
|
const letter = str[i]
|
|
166
184
|
const color = colorScheme[letter.toUpperCase()]
|
|
167
|
-
const contrast =
|
|
185
|
+
const contrast = contrastLettering
|
|
186
|
+
? contrastScheme[letter.toUpperCase()] || 'black'
|
|
187
|
+
: 'black'
|
|
168
188
|
const x = i * colWidth + offsetX - (offsetX % colWidth)
|
|
169
189
|
|
|
170
190
|
// note: -rowHeight/4 matches +rowHeight/4 in tree
|
|
171
|
-
ctx.fillStyle =
|
|
191
|
+
ctx.fillStyle = actuallyShowDomains
|
|
172
192
|
? 'black'
|
|
173
193
|
: bgColor
|
|
174
194
|
? contrast
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useEffect, useRef, useState } from 'react'
|
|
2
3
|
import { observer } from 'mobx-react'
|
|
3
4
|
|
|
4
5
|
// locals
|
|
5
|
-
import { MsaViewModel } from '../../model'
|
|
6
|
+
import type { MsaViewModel } from '../../model'
|
|
6
7
|
import TreeCanvasBlock from './TreeCanvasBlock'
|
|
7
8
|
import { padding } from './renderTreeCanvas'
|
|
8
9
|
|
|
@@ -48,7 +49,8 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
48
49
|
const distanceY = currY - prevY.current
|
|
49
50
|
if (distanceY) {
|
|
50
51
|
// use rAF to make it so multiple event handlers aren't fired per-frame
|
|
51
|
-
// see
|
|
52
|
+
// see
|
|
53
|
+
// https://calendar.perfplanet.com/2013/the-runtime-performance-checklist/
|
|
52
54
|
if (!scheduled.current) {
|
|
53
55
|
scheduled.current = true
|
|
54
56
|
window.requestAnimationFrame(() => {
|
|
@@ -92,23 +94,20 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
// this local mouseup is used in addition to the global because sometimes
|
|
96
|
-
// the global add/remove are not called in time, resulting in issue #533
|
|
97
|
-
function mouseUp(event: React.MouseEvent) {
|
|
98
|
-
event.preventDefault()
|
|
99
|
-
setMouseDragging(false)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function mouseLeave(event: React.MouseEvent) {
|
|
103
|
-
event.preventDefault()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
97
|
return (
|
|
107
98
|
<div
|
|
108
99
|
ref={ref}
|
|
109
100
|
onMouseDown={mouseDown}
|
|
110
|
-
onMouseUp={
|
|
111
|
-
|
|
101
|
+
onMouseUp={event => {
|
|
102
|
+
// this local mouseup is used in addition to the global because
|
|
103
|
+
// sometimes the global add/remove are not called in time, resulting in
|
|
104
|
+
// issue #533
|
|
105
|
+
event.preventDefault()
|
|
106
|
+
setMouseDragging(false)
|
|
107
|
+
}}
|
|
108
|
+
onMouseLeave={event => {
|
|
109
|
+
event.preventDefault()
|
|
110
|
+
}}
|
|
112
111
|
style={{
|
|
113
112
|
height,
|
|
114
113
|
position: 'relative',
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
3
|
import { autorun } from 'mobx'
|
|
3
4
|
import { observer } from 'mobx-react'
|
|
4
5
|
import { useTheme } from '@mui/material'
|
|
5
6
|
import RBush from 'rbush'
|
|
6
7
|
|
|
7
8
|
// locals
|
|
8
|
-
import { MsaViewModel } from '../../model'
|
|
9
|
+
import type { MsaViewModel } from '../../model'
|
|
9
10
|
import TreeNodeMenu from './TreeNodeMenu'
|
|
10
11
|
import TreeBranchMenu from './TreeBranchMenu'
|
|
11
12
|
import { padding, renderTreeCanvas } from './renderTreeCanvas'
|
|
@@ -3,7 +3,7 @@ import { Menu, MenuItem } from '@mui/material'
|
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
4
|
|
|
5
5
|
// locals
|
|
6
|
-
import { MsaViewModel } from '../../model'
|
|
6
|
+
import type { MsaViewModel } from '../../model'
|
|
7
7
|
|
|
8
8
|
// lazies
|
|
9
9
|
const TreeNodeInfoDialog = lazy(() => import('./dialogs/TreeNodeInfoDialog'))
|
|
@@ -17,7 +17,7 @@ const TreeMenu = observer(function ({
|
|
|
17
17
|
model: MsaViewModel
|
|
18
18
|
onClose: () => void
|
|
19
19
|
}) {
|
|
20
|
-
const { collapsed,
|
|
20
|
+
const { collapsed, collapsedLeaves } = model
|
|
21
21
|
return (
|
|
22
22
|
<Menu
|
|
23
23
|
anchorReference="anchorPosition"
|
|
@@ -66,7 +66,7 @@ const TreeMenu = observer(function ({
|
|
|
66
66
|
onClose()
|
|
67
67
|
}}
|
|
68
68
|
>
|
|
69
|
-
{collapsed.includes(node.id) ||
|
|
69
|
+
{collapsed.includes(node.id) || collapsedLeaves.includes(node.id)
|
|
70
70
|
? 'Show node'
|
|
71
71
|
: 'Hide node'}
|
|
72
72
|
</MenuItem>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
3
|
|
|
4
|
-
import { MsaViewModel } from '../../model'
|
|
4
|
+
import type { MsaViewModel } from '../../model'
|
|
5
5
|
import TreeCanvas from './TreeCanvas'
|
|
6
6
|
|
|
7
7
|
const TreePanel = observer(function ({ model }: { model: MsaViewModel }) {
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
3
|
|
|
4
4
|
// locals
|
|
5
|
-
import { MsaViewModel } from '../../model'
|
|
5
|
+
import type { MsaViewModel } from '../../model'
|
|
6
6
|
|
|
7
7
|
const TreeRuler = observer(({ model }: { model: MsaViewModel }) => {
|
|
8
8
|
const { treeAreaWidth } = model
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail'
|
|
9
9
|
|
|
10
10
|
// locals
|
|
11
|
-
import { MsaViewModel } from '../../../model'
|
|
11
|
+
import type { MsaViewModel } from '../../../model'
|
|
12
12
|
import SequenceTextArea from '../../SequenceTextArea'
|
|
13
13
|
|
|
14
14
|
export default observer(function ({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import RBush from 'rbush'
|
|
2
|
-
import { Theme } from '@mui/material'
|
|
1
|
+
import type RBush from 'rbush'
|
|
2
|
+
import type { Theme } from '@mui/material'
|
|
3
3
|
|
|
4
4
|
// locals
|
|
5
|
-
import { MsaViewModel } from '../../model'
|
|
5
|
+
import type { MsaViewModel } from '../../model'
|
|
6
6
|
|
|
7
7
|
export const padding = 600
|
|
8
8
|
|
|
@@ -38,6 +38,9 @@ export function renderTree({
|
|
|
38
38
|
ctx.strokeStyle = theme.palette.text.primary
|
|
39
39
|
for (const link of hierarchy.links()) {
|
|
40
40
|
const { source, target } = link
|
|
41
|
+
if (target.height === 0 && !showBranchLen) {
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
41
44
|
const sy = source.x!
|
|
42
45
|
const ty = target.x!
|
|
43
46
|
// @ts-expect-error
|
|
@@ -87,10 +90,9 @@ export function renderNodeBubbles({
|
|
|
87
90
|
// @ts-expect-error
|
|
88
91
|
const { [val]: x, data } = node
|
|
89
92
|
const y = node.x!
|
|
90
|
-
const {
|
|
93
|
+
const { id = '', name = '' } = data
|
|
91
94
|
if (
|
|
92
|
-
|
|
93
|
-
branchset.length &&
|
|
95
|
+
node.height > 1 &&
|
|
94
96
|
y > offsetY - extendBounds &&
|
|
95
97
|
y < offsetY + by + extendBounds
|
|
96
98
|
) {
|
|
@@ -134,13 +136,19 @@ export function renderTreeLabels({
|
|
|
134
136
|
showBranchLen,
|
|
135
137
|
treeMetadata,
|
|
136
138
|
hierarchy,
|
|
139
|
+
collapsed,
|
|
140
|
+
collapsedLeaves,
|
|
137
141
|
blockSize,
|
|
138
142
|
labelsAlignRight,
|
|
139
143
|
drawTree,
|
|
140
144
|
treeAreaWidth,
|
|
145
|
+
treeWidth,
|
|
141
146
|
treeAreaWidthMinusMargin,
|
|
142
147
|
marginLeft,
|
|
148
|
+
leaves,
|
|
143
149
|
noTree,
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
151
|
+
rowHeight: _rowHeight, // this is needed for redrawing after zoom change
|
|
144
152
|
} = model
|
|
145
153
|
const by = blockSizeYOverride || blockSize
|
|
146
154
|
if (labelsAlignRight) {
|
|
@@ -149,7 +157,7 @@ export function renderTreeLabels({
|
|
|
149
157
|
} else {
|
|
150
158
|
ctx.textAlign = 'start'
|
|
151
159
|
}
|
|
152
|
-
for (const node of
|
|
160
|
+
for (const node of leaves) {
|
|
153
161
|
const {
|
|
154
162
|
data: { name, id },
|
|
155
163
|
// @ts-expect-error
|
|
@@ -162,7 +170,18 @@ export function renderTreeLabels({
|
|
|
162
170
|
if (y > offsetY - extendBounds && y < offsetY + by + extendBounds) {
|
|
163
171
|
// note: +rowHeight/4 matches with -rowHeight/4 in msa
|
|
164
172
|
const yp = y + fontSize / 4
|
|
165
|
-
|
|
173
|
+
let xp = (showBranchLen ? len : x) || 0
|
|
174
|
+
if (
|
|
175
|
+
!showBranchLen &&
|
|
176
|
+
!collapsed.includes(id) &&
|
|
177
|
+
!collapsedLeaves.includes(id)
|
|
178
|
+
) {
|
|
179
|
+
// this subtraction is a hack to compensate for the leafnode rendering
|
|
180
|
+
// glitch (issue #71). the context is that an extra leaf node is added
|
|
181
|
+
// so that 'collapsing/hiding leaf nodes is possible' but this causes
|
|
182
|
+
// weird workarounds
|
|
183
|
+
xp -= treeWidth / hierarchy.height
|
|
184
|
+
}
|
|
166
185
|
|
|
167
186
|
const { width } = ctx.measureText(displayName)
|
|
168
187
|
const height = ctx.measureText('M').width // use an 'em' for height
|
|
@@ -223,13 +242,12 @@ export function renderTreeCanvas({
|
|
|
223
242
|
const {
|
|
224
243
|
noTree,
|
|
225
244
|
drawTree,
|
|
226
|
-
drawLabels,
|
|
227
245
|
drawNodeBubbles,
|
|
228
246
|
treeWidth,
|
|
229
247
|
highResScaleFactor,
|
|
230
248
|
blockSize,
|
|
231
249
|
fontSize,
|
|
232
|
-
|
|
250
|
+
showTreeText,
|
|
233
251
|
marginLeft,
|
|
234
252
|
nref,
|
|
235
253
|
} = model
|
|
@@ -243,7 +261,9 @@ export function renderTreeCanvas({
|
|
|
243
261
|
// is updated and in order to convince bundlers like not to delete unused
|
|
244
262
|
// usage with propertyReadSideEffects
|
|
245
263
|
const k =
|
|
246
|
-
nref < 0
|
|
264
|
+
nref < 0
|
|
265
|
+
? Number.NEGATIVE_INFINITY
|
|
266
|
+
: highResScaleFactorOverride || highResScaleFactor
|
|
247
267
|
ctx.scale(k, k)
|
|
248
268
|
ctx.clearRect(0, 0, treeWidth + padding, by)
|
|
249
269
|
ctx.translate(marginLeft, -offsetY)
|
|
@@ -272,7 +292,7 @@ export function renderTreeCanvas({
|
|
|
272
292
|
}
|
|
273
293
|
}
|
|
274
294
|
|
|
275
|
-
if (
|
|
295
|
+
if (showTreeText) {
|
|
276
296
|
renderTreeLabels({
|
|
277
297
|
ctx,
|
|
278
298
|
offsetY,
|
package/src/components/util.ts
CHANGED
|
@@ -10,7 +10,7 @@ export function chooseGridPitch(
|
|
|
10
10
|
) {
|
|
11
11
|
scale = Math.abs(scale)
|
|
12
12
|
const minMajorPitchBp = minMajorPitchPx * scale
|
|
13
|
-
const majorMagnitude = parseInt(
|
|
13
|
+
const majorMagnitude = Number.parseInt(
|
|
14
14
|
Number(minMajorPitchBp).toExponential().split(/e/i)[1],
|
|
15
15
|
10,
|
|
16
16
|
)
|
package/src/fetchUtils.ts
CHANGED
|
@@ -15,9 +15,9 @@ export async function textfetch(url: string, args?: RequestInit) {
|
|
|
15
15
|
return response.text()
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export async function jsonfetch(url: string, args?: RequestInit) {
|
|
18
|
+
export async function jsonfetch<T>(url: string, args?: RequestInit) {
|
|
19
19
|
const response = await myfetch(url, args)
|
|
20
|
-
return response.json()
|
|
20
|
+
return response.json() as T
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export async function arraybufferfetch(url: string) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { getSession } from '@jbrowse/core/util'
|
|
1
2
|
import { jsonfetch, textfetch, timeout } from './fetchUtils'
|
|
3
|
+
import type { MsaViewModel } from './model'
|
|
2
4
|
|
|
3
|
-
const base =
|
|
5
|
+
const base = 'https://www.ebi.ac.uk/Tools/services/rest'
|
|
4
6
|
|
|
5
7
|
export interface InterProScanResults {
|
|
6
8
|
matches: {
|
|
@@ -24,11 +26,13 @@ async function runInterProScan({
|
|
|
24
26
|
onProgress,
|
|
25
27
|
onJobId,
|
|
26
28
|
programs,
|
|
29
|
+
model,
|
|
27
30
|
}: {
|
|
28
31
|
seq: string
|
|
29
32
|
programs: string[]
|
|
30
33
|
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
31
|
-
onJobId
|
|
34
|
+
onJobId?: (arg: string) => void
|
|
35
|
+
model: MsaViewModel
|
|
32
36
|
}) {
|
|
33
37
|
const jobId = await textfetch(`${base}/iprscan5/run`, {
|
|
34
38
|
method: 'POST',
|
|
@@ -38,18 +42,18 @@ async function runInterProScan({
|
|
|
38
42
|
programs: programs.join(','),
|
|
39
43
|
}),
|
|
40
44
|
})
|
|
41
|
-
onJobId(jobId)
|
|
45
|
+
onJobId?.(jobId)
|
|
42
46
|
await wait({
|
|
43
47
|
jobId,
|
|
44
48
|
onProgress,
|
|
45
49
|
})
|
|
46
|
-
return
|
|
50
|
+
return loadInterProScanResultsWithStatus({ jobId, model })
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
export
|
|
50
|
-
return
|
|
53
|
+
export function loadInterProScanResults(jobId: string) {
|
|
54
|
+
return jsonfetch<InterProScanResponse>(
|
|
51
55
|
`${base}/iprscan5/result/${jobId}/json`,
|
|
52
|
-
)
|
|
56
|
+
)
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
async function wait({
|
|
@@ -60,17 +64,22 @@ async function wait({
|
|
|
60
64
|
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
61
65
|
}) {
|
|
62
66
|
const url = `${base}/iprscan5/status/${jobId}`
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
try {
|
|
68
|
+
while (true) {
|
|
69
|
+
for (let i = 0; i < 10; i++) {
|
|
70
|
+
await timeout(1000)
|
|
71
|
+
onProgress({ msg: `Checking status ${10 - i}`, url })
|
|
72
|
+
}
|
|
73
|
+
const result = await textfetch(url)
|
|
74
|
+
if (result.includes('FINISHED')) {
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
if (result.includes('FAILURE')) {
|
|
78
|
+
throw new Error(`Failed to run: jobId ${jobId}`)
|
|
79
|
+
}
|
|
73
80
|
}
|
|
81
|
+
} finally {
|
|
82
|
+
onProgress()
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
85
|
|
|
@@ -80,19 +89,55 @@ export async function launchInterProScan({
|
|
|
80
89
|
programs,
|
|
81
90
|
onJobId,
|
|
82
91
|
onProgress,
|
|
92
|
+
model,
|
|
83
93
|
}: {
|
|
84
94
|
algorithm: string
|
|
85
95
|
seq: string
|
|
86
96
|
programs: string[]
|
|
87
97
|
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
88
|
-
onJobId
|
|
98
|
+
onJobId?: (arg: string) => void
|
|
99
|
+
model: MsaViewModel
|
|
89
100
|
}) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
try {
|
|
102
|
+
onProgress({ msg: `Launching ${algorithm} MSA` })
|
|
103
|
+
if (algorithm === 'interproscan') {
|
|
104
|
+
const result = await runInterProScan({
|
|
105
|
+
seq,
|
|
106
|
+
onJobId,
|
|
107
|
+
onProgress,
|
|
108
|
+
programs,
|
|
109
|
+
model,
|
|
110
|
+
})
|
|
111
|
+
return result
|
|
112
|
+
}
|
|
96
113
|
throw new Error('unknown algorithm')
|
|
114
|
+
} finally {
|
|
115
|
+
onProgress()
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function loadInterProScanResultsWithStatus({
|
|
120
|
+
jobId,
|
|
121
|
+
model,
|
|
122
|
+
}: {
|
|
123
|
+
jobId: string
|
|
124
|
+
model: MsaViewModel
|
|
125
|
+
}) {
|
|
126
|
+
try {
|
|
127
|
+
model.setStatus({
|
|
128
|
+
msg: `Downloading results of ${jobId} (for larger sequences this can be slow, click status to download and upload in the manual tab)`,
|
|
129
|
+
url: `https://www.ebi.ac.uk/Tools/services/rest/iprscan5/result/${jobId}/json`,
|
|
130
|
+
})
|
|
131
|
+
const ret = await loadInterProScanResults(jobId)
|
|
132
|
+
model.setInterProAnnotations(
|
|
133
|
+
Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
|
|
134
|
+
)
|
|
135
|
+
model.setShowDomains(true)
|
|
136
|
+
getSession(model).notify(`Loaded interproscan ${jobId} results`, 'success')
|
|
137
|
+
} catch (e) {
|
|
138
|
+
console.error(e)
|
|
139
|
+
getSession(model).notifyError(`${e}`, e)
|
|
140
|
+
} finally {
|
|
141
|
+
model.setStatus()
|
|
97
142
|
}
|
|
98
143
|
}
|
package/src/model/DataModel.ts
CHANGED
|
@@ -43,4 +43,14 @@ export function DataModelF() {
|
|
|
43
43
|
self.treeMetadata = treeMetadata
|
|
44
44
|
},
|
|
45
45
|
}))
|
|
46
|
+
.postProcessSnapshot(snap => {
|
|
47
|
+
const { tree, msa, treeMetadata } = snap
|
|
48
|
+
const max = 50_000
|
|
49
|
+
return {
|
|
50
|
+
tree: tree && tree.length > max ? undefined : tree,
|
|
51
|
+
msa: msa && msa.length > max ? undefined : msa,
|
|
52
|
+
treeMetadata:
|
|
53
|
+
treeMetadata && treeMetadata.length > max ? undefined : treeMetadata,
|
|
54
|
+
}
|
|
55
|
+
})
|
|
46
56
|
}
|
package/src/model/DialogQueue.ts
CHANGED