jbrowse-plugin-mafviewer 1.2.3 → 1.3.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/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.d.ts +1 -1
- package/dist/BigMafAdapter/BigMafAdapter.d.ts +1 -1
- package/dist/BigMafAdapter/BigMafAdapter.js +50 -49
- package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
- package/dist/LinearMafDisplay/components/Crosshairs.d.ts +10 -0
- package/dist/LinearMafDisplay/components/Crosshairs.js +18 -0
- package/dist/LinearMafDisplay/components/Crosshairs.js.map +1 -0
- package/dist/LinearMafDisplay/components/GetSequenceDialog/GetSequenceDialog.d.ts +11 -0
- package/dist/LinearMafDisplay/components/GetSequenceDialog/GetSequenceDialog.js +97 -0
- package/dist/LinearMafDisplay/components/GetSequenceDialog/GetSequenceDialog.js.map +1 -0
- package/dist/LinearMafDisplay/components/{ReactComponent.d.ts → LinearMafDisplayComponent.d.ts} +1 -1
- package/dist/LinearMafDisplay/components/LinearMafDisplayComponent.js +168 -0
- package/dist/LinearMafDisplay/components/LinearMafDisplayComponent.js.map +1 -0
- package/dist/LinearMafDisplay/components/MAFTooltip.d.ts +12 -0
- package/dist/LinearMafDisplay/components/MAFTooltip.js +29 -0
- package/dist/LinearMafDisplay/components/MAFTooltip.js.map +1 -0
- package/dist/LinearMafDisplay/components/SetRowHeightDialog/SetRowHeightDialog.js +38 -0
- package/dist/LinearMafDisplay/components/SetRowHeightDialog/SetRowHeightDialog.js.map +1 -0
- package/dist/LinearMafDisplay/components/Sidebar/ColorLegend.d.ts +6 -0
- package/dist/LinearMafDisplay/components/{ColorLegend.js → Sidebar/ColorLegend.js} +2 -3
- package/dist/LinearMafDisplay/components/Sidebar/ColorLegend.js.map +1 -0
- package/dist/LinearMafDisplay/components/Sidebar/RectBg.js.map +1 -0
- package/dist/LinearMafDisplay/components/{SvgWrapper.d.ts → Sidebar/SvgWrapper.d.ts} +1 -1
- package/dist/LinearMafDisplay/components/{SvgWrapper.js → Sidebar/SvgWrapper.js} +3 -1
- package/dist/LinearMafDisplay/components/Sidebar/SvgWrapper.js.map +1 -0
- package/dist/LinearMafDisplay/components/{Tree.d.ts → Sidebar/Tree.d.ts} +2 -1
- package/dist/LinearMafDisplay/components/{Tree.js → Sidebar/Tree.js} +2 -0
- package/dist/LinearMafDisplay/components/Sidebar/Tree.js.map +1 -0
- package/dist/LinearMafDisplay/components/{YScaleBars.d.ts → Sidebar/YScaleBars.d.ts} +1 -1
- package/dist/LinearMafDisplay/components/Sidebar/YScaleBars.js +11 -0
- package/dist/LinearMafDisplay/components/Sidebar/YScaleBars.js.map +1 -0
- package/dist/LinearMafDisplay/index.js +1 -1
- package/dist/LinearMafDisplay/index.js.map +1 -1
- package/dist/LinearMafDisplay/renderSvg.js +1 -1
- package/dist/LinearMafDisplay/renderSvg.js.map +1 -1
- package/dist/LinearMafDisplay/stateModel.d.ts +23 -20
- package/dist/LinearMafDisplay/stateModel.js +62 -8
- package/dist/LinearMafDisplay/stateModel.js.map +1 -1
- package/dist/LinearMafDisplay/types.d.ts +5 -3
- package/dist/LinearMafDisplay/types.js +1 -15
- package/dist/LinearMafDisplay/types.js.map +1 -1
- package/dist/LinearMafDisplay/util.d.ts +4 -0
- package/dist/LinearMafDisplay/util.js +16 -0
- package/dist/LinearMafDisplay/util.js.map +1 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +5 -4
- package/dist/LinearMafRenderer/LinearMafRenderer.js +8 -10
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
- package/dist/LinearMafRenderer/makeImageData.d.ts +1 -0
- package/dist/LinearMafRenderer/makeImageData.js +25 -20
- package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
- package/dist/MafAddTrackWorkflow/index.js +0 -1
- package/dist/MafAddTrackWorkflow/index.js.map +1 -1
- package/dist/{MafRPC/index.d.ts → MafGetSamples/MafGetSamples.d.ts} +1 -3
- package/dist/{MafRPC/index.js → MafGetSamples/MafGetSamples.js} +2 -7
- package/dist/MafGetSamples/MafGetSamples.js.map +1 -0
- package/dist/MafGetSamples/index.d.ts +2 -0
- package/dist/MafGetSamples/index.js +7 -0
- package/dist/MafGetSamples/index.js.map +1 -0
- package/dist/MafGetSequences/MafGetSequences.d.ts +16 -0
- package/dist/MafGetSequences/MafGetSequences.js +20 -0
- package/dist/MafGetSequences/MafGetSequences.js.map +1 -0
- package/dist/MafGetSequences/index.d.ts +2 -0
- package/dist/MafGetSequences/index.js +7 -0
- package/dist/MafGetSequences/index.js.map +1 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +1 -1
- package/dist/MafTabixAdapter/MafTabixAdapter.js +9 -11
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
- package/dist/MafTabixAdapter/configSchema.js +29 -1
- package/dist/MafTabixAdapter/configSchema.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +9 -20
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/util/extractSubsequence.d.ts +12 -0
- package/dist/util/extractSubsequence.js +60 -0
- package/dist/util/extractSubsequence.js.map +1 -0
- package/dist/util/extractSubsequence.test.d.ts +1 -0
- package/dist/util/extractSubsequence.test.js +42 -0
- package/dist/util/extractSubsequence.test.js.map +1 -0
- package/dist/util/fastaUtils.d.ts +16 -0
- package/dist/util/fastaUtils.js +84 -0
- package/dist/util/fastaUtils.js.map +1 -0
- package/dist/util/fastaUtils.test.d.ts +1 -0
- package/dist/util/fastaUtils.test.js +95 -0
- package/dist/util/fastaUtils.test.js.map +1 -0
- package/dist/util/fetchSequences.d.ts +18 -0
- package/dist/util/fetchSequences.js +39 -0
- package/dist/util/fetchSequences.js.map +1 -0
- package/dist/util/useSequences.d.ts +21 -0
- package/dist/util/useSequences.js +64 -0
- package/dist/util/useSequences.js.map +1 -0
- package/dist/util.d.ts +2 -2
- package/dist/util.js +5 -1
- package/dist/util.js.map +1 -1
- package/package.json +13 -13
- package/src/BigMafAdapter/BigMafAdapter.ts +52 -49
- package/src/LinearMafDisplay/components/Crosshairs.tsx +50 -0
- package/src/LinearMafDisplay/components/GetSequenceDialog/GetSequenceDialog.tsx +175 -0
- package/src/LinearMafDisplay/components/LinearMafDisplayComponent.tsx +257 -0
- package/src/LinearMafDisplay/components/MAFTooltip.tsx +59 -0
- package/src/LinearMafDisplay/components/SetRowHeightDialog/SetRowHeightDialog.tsx +83 -0
- package/src/LinearMafDisplay/components/{ColorLegend.tsx → Sidebar/ColorLegend.tsx} +11 -7
- package/src/LinearMafDisplay/components/{SvgWrapper.tsx → Sidebar/SvgWrapper.tsx} +5 -3
- package/src/LinearMafDisplay/components/{Tree.tsx → Sidebar/Tree.tsx} +5 -1
- package/src/LinearMafDisplay/components/Sidebar/YScaleBars.tsx +23 -0
- package/src/LinearMafDisplay/index.ts +1 -1
- package/src/LinearMafDisplay/renderSvg.tsx +1 -1
- package/src/LinearMafDisplay/stateModel.ts +71 -18
- package/src/LinearMafDisplay/types.ts +4 -24
- package/src/LinearMafDisplay/util.ts +27 -0
- package/src/LinearMafRenderer/LinearMafRenderer.ts +10 -14
- package/src/LinearMafRenderer/makeImageData.ts +33 -22
- package/src/MafAddTrackWorkflow/index.ts +0 -1
- package/src/{MafRPC/index.ts → MafGetSamples/MafGetSamples.ts} +1 -8
- package/src/MafGetSamples/index.ts +9 -0
- package/src/MafGetSequences/MafGetSequences.ts +47 -0
- package/src/MafGetSequences/index.ts +9 -0
- package/src/MafTabixAdapter/MafTabixAdapter.ts +13 -12
- package/src/MafTabixAdapter/configSchema.ts +29 -1
- package/src/index.ts +4 -2
- package/src/util/__snapshots__/fastaUtils.test.ts.snap +22 -0
- package/src/util/extractSubsequence.test.ts +54 -0
- package/src/util/extractSubsequence.ts +74 -0
- package/src/util/fastaUtils.test.ts +99 -0
- package/src/util/fastaUtils.ts +102 -0
- package/src/util/fetchSequences.ts +57 -0
- package/src/util/useSequences.ts +90 -0
- package/src/util.ts +6 -2
- package/dist/LinearMafDisplay/components/ColorLegend.d.ts +0 -8
- package/dist/LinearMafDisplay/components/ColorLegend.js.map +0 -1
- package/dist/LinearMafDisplay/components/ReactComponent.js +0 -50
- package/dist/LinearMafDisplay/components/ReactComponent.js.map +0 -1
- package/dist/LinearMafDisplay/components/RectBg.js.map +0 -1
- package/dist/LinearMafDisplay/components/SetRowHeight.js +0 -36
- package/dist/LinearMafDisplay/components/SetRowHeight.js.map +0 -1
- package/dist/LinearMafDisplay/components/SvgWrapper.js.map +0 -1
- package/dist/LinearMafDisplay/components/Tree.js.map +0 -1
- package/dist/LinearMafDisplay/components/YScaleBars.js +0 -20
- package/dist/LinearMafDisplay/components/YScaleBars.js.map +0 -1
- package/dist/MafRPC/index.js.map +0 -1
- package/src/LinearMafDisplay/components/ReactComponent.tsx +0 -91
- package/src/LinearMafDisplay/components/SetRowHeight.tsx +0 -83
- package/src/LinearMafDisplay/components/YScaleBars.tsx +0 -41
- /package/dist/LinearMafDisplay/components/{SetRowHeight.d.ts → SetRowHeightDialog/SetRowHeightDialog.d.ts} +0 -0
- /package/dist/LinearMafDisplay/components/{RectBg.d.ts → Sidebar/RectBg.d.ts} +0 -0
- /package/dist/LinearMafDisplay/components/{RectBg.js → Sidebar/RectBg.js} +0 -0
- /package/src/LinearMafDisplay/components/{RectBg.tsx → Sidebar/RectBg.tsx} +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Dialog } from '@jbrowse/core/ui'
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
DialogActions,
|
|
7
|
+
DialogContent,
|
|
8
|
+
TextField,
|
|
9
|
+
Typography,
|
|
10
|
+
} from '@mui/material'
|
|
11
|
+
import { observer } from 'mobx-react'
|
|
12
|
+
import { makeStyles } from 'tss-react/mui'
|
|
13
|
+
|
|
14
|
+
const useStyles = makeStyles()({
|
|
15
|
+
root: {
|
|
16
|
+
width: 500,
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const SetRowHeightDialog = observer(function (props: {
|
|
21
|
+
model: {
|
|
22
|
+
rowHeight?: number
|
|
23
|
+
rowProportion?: number
|
|
24
|
+
setRowHeight: (arg: number) => void
|
|
25
|
+
setRowProportion: (arg: number) => void
|
|
26
|
+
}
|
|
27
|
+
handleClose: () => void
|
|
28
|
+
}) {
|
|
29
|
+
const { model, handleClose } = props
|
|
30
|
+
const { classes } = useStyles()
|
|
31
|
+
const [rowHeight, setRowHeight] = useState(`${model.rowHeight}`)
|
|
32
|
+
const [rowProportion, setRowProportion] = useState(`${model.rowProportion}`)
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Dialog open onClose={handleClose} title="Set row height">
|
|
36
|
+
<form
|
|
37
|
+
onSubmit={event => {
|
|
38
|
+
event.preventDefault()
|
|
39
|
+
model.setRowProportion(+rowProportion)
|
|
40
|
+
model.setRowHeight(+rowHeight)
|
|
41
|
+
handleClose()
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<DialogContent className={classes.root}>
|
|
45
|
+
<Typography>
|
|
46
|
+
Set row height and the proportion of the row height to use for
|
|
47
|
+
drawing each row
|
|
48
|
+
</Typography>
|
|
49
|
+
<TextField
|
|
50
|
+
value={rowHeight}
|
|
51
|
+
helperText="Enter row height"
|
|
52
|
+
autoFocus
|
|
53
|
+
onChange={event => {
|
|
54
|
+
setRowHeight(event.target.value)
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
<TextField
|
|
58
|
+
value={rowProportion}
|
|
59
|
+
helperText="Enter row proportion"
|
|
60
|
+
onChange={event => {
|
|
61
|
+
setRowProportion(event.target.value)
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
<DialogActions>
|
|
65
|
+
<Button variant="contained" color="primary" type="submit">
|
|
66
|
+
Submit
|
|
67
|
+
</Button>
|
|
68
|
+
<Button
|
|
69
|
+
variant="contained"
|
|
70
|
+
color="secondary"
|
|
71
|
+
onClick={() => {
|
|
72
|
+
handleClose()
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
Cancel
|
|
76
|
+
</Button>
|
|
77
|
+
</DialogActions>
|
|
78
|
+
</DialogContent>
|
|
79
|
+
</form>
|
|
80
|
+
</Dialog>
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
export default SetRowHeightDialog
|
|
@@ -2,21 +2,25 @@ import React from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
4
|
|
|
5
|
-
import { LinearMafDisplayModel } from '../stateModel'
|
|
6
5
|
import RectBg from './RectBg'
|
|
7
6
|
import Tree from './Tree'
|
|
8
7
|
|
|
8
|
+
import type { LinearMafDisplayModel } from '../../stateModel'
|
|
9
|
+
|
|
9
10
|
const ColorLegend = observer(function ({
|
|
10
11
|
model,
|
|
11
|
-
labelWidth,
|
|
12
|
-
svgFontSize,
|
|
13
12
|
}: {
|
|
14
13
|
model: LinearMafDisplayModel
|
|
15
|
-
svgFontSize: number
|
|
16
|
-
labelWidth: number
|
|
17
14
|
}) {
|
|
18
|
-
const {
|
|
19
|
-
|
|
15
|
+
const {
|
|
16
|
+
labelWidth,
|
|
17
|
+
canDisplayLabel,
|
|
18
|
+
totalHeight,
|
|
19
|
+
treeWidth,
|
|
20
|
+
samples = [],
|
|
21
|
+
rowHeight,
|
|
22
|
+
svgFontSize,
|
|
23
|
+
} = model
|
|
20
24
|
const boxHeight = Math.min(20, rowHeight)
|
|
21
25
|
|
|
22
26
|
return (
|
|
@@ -3,8 +3,8 @@ import React from 'react'
|
|
|
3
3
|
import { getContainingView } from '@jbrowse/core/util'
|
|
4
4
|
import { observer } from 'mobx-react'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
import {
|
|
6
|
+
import type { LinearMafDisplayModel } from '../../stateModel'
|
|
7
|
+
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
8
8
|
|
|
9
9
|
const SvgWrapper = observer(function ({
|
|
10
10
|
children,
|
|
@@ -19,15 +19,17 @@ const SvgWrapper = observer(function ({
|
|
|
19
19
|
return <>{children}</>
|
|
20
20
|
} else {
|
|
21
21
|
const { totalHeight } = model
|
|
22
|
+
const { width } = getContainingView(model) as LinearGenomeViewModel
|
|
22
23
|
return (
|
|
23
24
|
<svg
|
|
24
25
|
style={{
|
|
25
26
|
position: 'absolute',
|
|
27
|
+
userSelect: 'none',
|
|
26
28
|
top: 0,
|
|
27
29
|
left: 0,
|
|
28
30
|
pointerEvents: 'none',
|
|
29
31
|
height: totalHeight,
|
|
30
|
-
width
|
|
32
|
+
width,
|
|
31
33
|
}}
|
|
32
34
|
>
|
|
33
35
|
{children}
|
|
@@ -2,7 +2,9 @@ import React from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import type { LinearMafDisplayModel } from '../../stateModel'
|
|
6
|
+
|
|
7
|
+
const Tree = observer(function ({ model }: { model: LinearMafDisplayModel }) {
|
|
6
8
|
const {
|
|
7
9
|
// this is needed for redrawing after zoom change, similar to react-msaview
|
|
8
10
|
// renderTreeCanvas
|
|
@@ -20,7 +22,9 @@ const Tree = observer(function ({ model }: { model: any }) {
|
|
|
20
22
|
const { source, target } = link
|
|
21
23
|
const sy = source.x!
|
|
22
24
|
const ty = target.x!
|
|
25
|
+
// @ts-expect-error
|
|
23
26
|
const tx = showBranchLen ? target.len : target.y
|
|
27
|
+
// @ts-expect-error
|
|
24
28
|
const sx = showBranchLen ? source.len : source.y
|
|
25
29
|
|
|
26
30
|
// 1d line intersection to check if line crosses block at all, this is
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { observer } from 'mobx-react'
|
|
4
|
+
|
|
5
|
+
import ColorLegend from './ColorLegend'
|
|
6
|
+
import SvgWrapper from './SvgWrapper'
|
|
7
|
+
|
|
8
|
+
import type { LinearMafDisplayModel } from '../../stateModel'
|
|
9
|
+
|
|
10
|
+
export const YScaleBars = observer(function (props: {
|
|
11
|
+
model: LinearMafDisplayModel
|
|
12
|
+
orientation?: string
|
|
13
|
+
exportSVG?: boolean
|
|
14
|
+
}) {
|
|
15
|
+
const { model } = props
|
|
16
|
+
return (
|
|
17
|
+
<SvgWrapper {...props}>
|
|
18
|
+
<ColorLegend model={model} />
|
|
19
|
+
</SvgWrapper>
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export default YScaleBars
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
2
|
import { DisplayType } from '@jbrowse/core/pluggableElementTypes'
|
|
3
3
|
|
|
4
|
-
import ReactComponent from './components/
|
|
4
|
+
import ReactComponent from './components/LinearMafDisplayComponent'
|
|
5
5
|
import configSchemaF from './configSchema'
|
|
6
6
|
import stateModelFactory from './stateModel'
|
|
7
7
|
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { getContainingView } from '@jbrowse/core/util'
|
|
4
4
|
|
|
5
|
-
import YScaleBars from './components/YScaleBars'
|
|
5
|
+
import YScaleBars from './components/Sidebar/YScaleBars'
|
|
6
6
|
|
|
7
7
|
import type { LinearMafDisplayModel } from './stateModel'
|
|
8
8
|
import type {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { lazy } from 'react'
|
|
2
|
+
|
|
1
3
|
import { ConfigurationReference, getConf } from '@jbrowse/core/configuration'
|
|
2
|
-
import { getEnv, getSession } from '@jbrowse/core/util'
|
|
4
|
+
import { getEnv, getSession, max, measureText } from '@jbrowse/core/util'
|
|
3
5
|
import { getRpcSessionId } from '@jbrowse/core/util/tracks'
|
|
4
6
|
import { ascending } from 'd3-array'
|
|
5
7
|
import { cluster, hierarchy } from 'd3-hierarchy'
|
|
@@ -7,11 +9,10 @@ import deepEqual from 'fast-deep-equal'
|
|
|
7
9
|
import { autorun } from 'mobx'
|
|
8
10
|
import { addDisposer, isAlive, types } from 'mobx-state-tree'
|
|
9
11
|
|
|
10
|
-
import
|
|
11
|
-
import { maxLength, setBrLength } from './types'
|
|
12
|
+
import { maxLength, setBrLength } from './util'
|
|
12
13
|
import { normalize } from '../util'
|
|
13
14
|
|
|
14
|
-
import type { NodeWithIds, NodeWithIdsAndLength } from './types'
|
|
15
|
+
import type { NodeWithIds, NodeWithIdsAndLength, Sample } from './types'
|
|
15
16
|
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
16
17
|
import type {
|
|
17
18
|
AnyConfigurationModel,
|
|
@@ -21,11 +22,9 @@ import type { ExportSvgDisplayOptions } from '@jbrowse/plugin-linear-genome-view
|
|
|
21
22
|
import type { HierarchyNode } from 'd3-hierarchy'
|
|
22
23
|
import type { Instance } from 'mobx-state-tree'
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
color?: string
|
|
28
|
-
}
|
|
25
|
+
const SetRowHeightDialog = lazy(
|
|
26
|
+
() => import('./components/SetRowHeightDialog/SetRowHeightDialog'),
|
|
27
|
+
)
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
30
|
* #stateModel LinearMafDisplay
|
|
@@ -79,6 +78,10 @@ export default function stateModelFactory(
|
|
|
79
78
|
* #property
|
|
80
79
|
*/
|
|
81
80
|
treeAreaWidth: 80,
|
|
81
|
+
/**
|
|
82
|
+
* #property
|
|
83
|
+
*/
|
|
84
|
+
showAsUpperCase: true,
|
|
82
85
|
}),
|
|
83
86
|
)
|
|
84
87
|
.volatile(() => ({
|
|
@@ -131,6 +134,12 @@ export default function stateModelFactory(
|
|
|
131
134
|
self.volatileTree = tree
|
|
132
135
|
}
|
|
133
136
|
},
|
|
137
|
+
/**
|
|
138
|
+
* #action
|
|
139
|
+
*/
|
|
140
|
+
setShowAsUpperCase(arg: boolean) {
|
|
141
|
+
self.showAsUpperCase = arg
|
|
142
|
+
},
|
|
134
143
|
}))
|
|
135
144
|
.views(self => ({
|
|
136
145
|
/**
|
|
@@ -193,8 +202,20 @@ export default function stateModelFactory(
|
|
|
193
202
|
* #getter
|
|
194
203
|
*/
|
|
195
204
|
get samples() {
|
|
196
|
-
|
|
205
|
+
if (this.rowNames) {
|
|
206
|
+
const volatileSamplesMap = self.volatileSamples
|
|
207
|
+
? Object.fromEntries(self.volatileSamples.map(e => [e.id, e]))
|
|
208
|
+
: undefined
|
|
209
|
+
return normalize(this.rowNames).map(r => ({
|
|
210
|
+
...r,
|
|
211
|
+
label: volatileSamplesMap?.[r.id]?.label || r.label,
|
|
212
|
+
color: volatileSamplesMap?.[r.id]?.color || r.color,
|
|
213
|
+
}))
|
|
214
|
+
} else {
|
|
215
|
+
return self.volatileSamples
|
|
216
|
+
}
|
|
197
217
|
},
|
|
218
|
+
|
|
198
219
|
/**
|
|
199
220
|
* #getter
|
|
200
221
|
*/
|
|
@@ -239,6 +260,7 @@ export default function stateModelFactory(
|
|
|
239
260
|
rowHeight,
|
|
240
261
|
rowProportion,
|
|
241
262
|
mismatchRendering,
|
|
263
|
+
showAsUpperCase,
|
|
242
264
|
} = self
|
|
243
265
|
const s = superRenderProps()
|
|
244
266
|
return {
|
|
@@ -251,6 +273,7 @@ export default function stateModelFactory(
|
|
|
251
273
|
rowProportion,
|
|
252
274
|
showAllLetters,
|
|
253
275
|
mismatchRendering,
|
|
276
|
+
showAsUpperCase,
|
|
254
277
|
}
|
|
255
278
|
},
|
|
256
279
|
/**
|
|
@@ -291,6 +314,14 @@ export default function stateModelFactory(
|
|
|
291
314
|
},
|
|
292
315
|
],
|
|
293
316
|
},
|
|
317
|
+
{
|
|
318
|
+
label: 'Use upper-case',
|
|
319
|
+
type: 'checkbox',
|
|
320
|
+
checked: self.showAsUpperCase,
|
|
321
|
+
onClick: () => {
|
|
322
|
+
self.setShowAsUpperCase(!self.showAsUpperCase)
|
|
323
|
+
},
|
|
324
|
+
},
|
|
294
325
|
{
|
|
295
326
|
label: 'Show all letters',
|
|
296
327
|
type: 'checkbox',
|
|
@@ -311,6 +342,32 @@ export default function stateModelFactory(
|
|
|
311
342
|
},
|
|
312
343
|
}
|
|
313
344
|
})
|
|
345
|
+
.views(self => ({
|
|
346
|
+
/**
|
|
347
|
+
* #getter
|
|
348
|
+
*/
|
|
349
|
+
get svgFontSize() {
|
|
350
|
+
return Math.min(Math.max(self.rowHeight, 8), 14)
|
|
351
|
+
},
|
|
352
|
+
/**
|
|
353
|
+
* #getter
|
|
354
|
+
*/
|
|
355
|
+
get canDisplayLabel() {
|
|
356
|
+
return self.rowHeight >= 7
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* #getter
|
|
360
|
+
*/
|
|
361
|
+
get labelWidth() {
|
|
362
|
+
const minWidth = 20
|
|
363
|
+
return max(
|
|
364
|
+
self.samples
|
|
365
|
+
?.map(s => measureText(s.label, this.svgFontSize))
|
|
366
|
+
.map(width => (this.canDisplayLabel ? width : minWidth)) || [],
|
|
367
|
+
0,
|
|
368
|
+
)
|
|
369
|
+
},
|
|
370
|
+
}))
|
|
314
371
|
.actions(self => ({
|
|
315
372
|
afterCreate() {
|
|
316
373
|
addDisposer(
|
|
@@ -319,11 +376,8 @@ export default function stateModelFactory(
|
|
|
319
376
|
try {
|
|
320
377
|
const { rpcManager } = getSession(self)
|
|
321
378
|
const sessionId = getRpcSessionId(self)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
sessionId,
|
|
325
|
-
'MafGetSamples',
|
|
326
|
-
{
|
|
379
|
+
self.setSamples(
|
|
380
|
+
(await rpcManager.call(sessionId, 'MafGetSamples', {
|
|
327
381
|
sessionId,
|
|
328
382
|
adapterConfig: self.adapterConfig,
|
|
329
383
|
statusCallback: (message: string) => {
|
|
@@ -331,9 +385,8 @@ export default function stateModelFactory(
|
|
|
331
385
|
self.setMessage(message)
|
|
332
386
|
}
|
|
333
387
|
},
|
|
334
|
-
},
|
|
335
|
-
)
|
|
336
|
-
self.setSamples(results)
|
|
388
|
+
})) as { samples: Sample[]; tree: unknown },
|
|
389
|
+
)
|
|
337
390
|
} catch (e) {
|
|
338
391
|
console.error(e)
|
|
339
392
|
getSession(self).notifyError(`${e}`, e)
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { max } from 'd3-array'
|
|
2
|
-
|
|
3
|
-
import type { HierarchyNode } from 'd3-hierarchy'
|
|
4
|
-
|
|
5
1
|
export interface NodeWithIds {
|
|
6
2
|
id: string
|
|
7
3
|
name: string
|
|
@@ -18,24 +14,8 @@ export interface NodeWithIdsAndLength {
|
|
|
18
14
|
length: number
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
// basically same as setRadius from https://observablehq.com/@d3/tree-of-life
|
|
28
|
-
export function setBrLength(
|
|
29
|
-
d: HierarchyNode<NodeWithIds>,
|
|
30
|
-
y0: number,
|
|
31
|
-
k: number,
|
|
32
|
-
) {
|
|
33
|
-
// @ts-expect-error
|
|
34
|
-
d.len = (y0 += Math.max(d.data.length || 0, 0)) * k
|
|
35
|
-
|
|
36
|
-
if (d.children) {
|
|
37
|
-
d.children.forEach(d => {
|
|
38
|
-
setBrLength(d, y0, k)
|
|
39
|
-
})
|
|
40
|
-
}
|
|
17
|
+
export interface Sample {
|
|
18
|
+
id: string
|
|
19
|
+
label?: string
|
|
20
|
+
color?: string
|
|
41
21
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { max } from 'd3-array'
|
|
2
|
+
|
|
3
|
+
import type { NodeWithIds } from './types'
|
|
4
|
+
import type { HierarchyNode } from 'd3-hierarchy'
|
|
5
|
+
|
|
6
|
+
// basically same as maxLength from https://observablehq.com/@d3/tree-of-life
|
|
7
|
+
export function maxLength(d: HierarchyNode<NodeWithIds>): number {
|
|
8
|
+
return (
|
|
9
|
+
(d.data.length || 0) + (d.children ? max(d.children, maxLength) || 0 : 0)
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// basically same as setRadius from https://observablehq.com/@d3/tree-of-life
|
|
14
|
+
export function setBrLength(
|
|
15
|
+
d: HierarchyNode<NodeWithIds>,
|
|
16
|
+
y0: number,
|
|
17
|
+
k: number,
|
|
18
|
+
) {
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
d.len = (y0 += Math.max(d.data.length || 0, 0)) * k
|
|
21
|
+
|
|
22
|
+
if (d.children) {
|
|
23
|
+
d.children.forEach(d => {
|
|
24
|
+
setBrLength(d, y0, k)
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -19,6 +19,7 @@ interface RenderArgs extends RenderArgsDeserialized {
|
|
|
19
19
|
showAllLetters: boolean
|
|
20
20
|
mismatchRendering: boolean
|
|
21
21
|
statusCallback?: (arg: string) => void
|
|
22
|
+
showAsUpperCase: boolean
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export default class LinearMafRenderer extends FeatureRendererType {
|
|
@@ -45,22 +46,17 @@ export default class LinearMafRenderer extends FeatureRendererType {
|
|
|
45
46
|
const height = samples.length * rowHeight + 100
|
|
46
47
|
const width = (region.end - region.start) / bpPerPx
|
|
47
48
|
const features = await this.getFeatures(renderProps)
|
|
48
|
-
const res = await
|
|
49
|
-
width,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
renderArgs: {
|
|
57
|
-
...renderProps,
|
|
58
|
-
features,
|
|
59
|
-
},
|
|
60
|
-
})
|
|
49
|
+
const res = await updateStatus('Rendering alignment', statusCallback, () =>
|
|
50
|
+
renderToAbstractCanvas(width, height, renderProps, ctx => {
|
|
51
|
+
makeImageData({
|
|
52
|
+
ctx,
|
|
53
|
+
renderArgs: {
|
|
54
|
+
...renderProps,
|
|
55
|
+
features,
|
|
56
|
+
},
|
|
61
57
|
})
|
|
62
58
|
return undefined
|
|
63
|
-
},
|
|
59
|
+
}),
|
|
64
60
|
)
|
|
65
61
|
const results = await super.render({
|
|
66
62
|
...renderProps,
|
|
@@ -21,6 +21,11 @@ interface RenderArgs extends RenderArgsDeserialized {
|
|
|
21
21
|
mismatchRendering: boolean
|
|
22
22
|
features: Map<string, Feature>
|
|
23
23
|
statusCallback?: (arg: string) => void
|
|
24
|
+
showAsUpperCase: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getLetter(a: string, showAsUpperCase: boolean) {
|
|
28
|
+
return showAsUpperCase ? a.toUpperCase() : a
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export function makeImageData({
|
|
@@ -40,6 +45,7 @@ export function makeImageData({
|
|
|
40
45
|
samples,
|
|
41
46
|
rowProportion,
|
|
42
47
|
features,
|
|
48
|
+
showAsUpperCase,
|
|
43
49
|
} = renderArgs
|
|
44
50
|
const region = regions[0]!
|
|
45
51
|
const canvasWidth = (region.end - region.start) / bpPerPx
|
|
@@ -61,11 +67,11 @@ export function makeImageData({
|
|
|
61
67
|
|
|
62
68
|
for (const feature of features.values()) {
|
|
63
69
|
const [leftPx] = featureSpanPx(feature, region, bpPerPx)
|
|
64
|
-
const vals = feature.get('alignments') as Record<string, {
|
|
70
|
+
const vals = feature.get('alignments') as Record<string, { seq: string }>
|
|
65
71
|
const seq = feature.get('seq').toLowerCase()
|
|
66
72
|
const r = Object.entries(vals)
|
|
67
73
|
for (const [sample, val] of r) {
|
|
68
|
-
const origAlignment = val.
|
|
74
|
+
const origAlignment = val.seq
|
|
69
75
|
const alignment = origAlignment.toLowerCase()
|
|
70
76
|
|
|
71
77
|
const row = sampleToRowMap.get(sample)
|
|
@@ -74,11 +80,12 @@ export function makeImageData({
|
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
const t = rowHeight * row
|
|
83
|
+
const t2 = offset + t
|
|
77
84
|
|
|
78
85
|
// gaps
|
|
79
86
|
ctx.beginPath()
|
|
80
87
|
ctx.fillStyle = 'black'
|
|
81
|
-
for (let i = 0, o = 0
|
|
88
|
+
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
82
89
|
if (seq[i] !== '-') {
|
|
83
90
|
if (alignment[i] === '-') {
|
|
84
91
|
const l = leftPx + scale * o
|
|
@@ -93,12 +100,12 @@ export function makeImageData({
|
|
|
93
100
|
if (!showAllLetters) {
|
|
94
101
|
// matches
|
|
95
102
|
ctx.fillStyle = 'lightgrey'
|
|
96
|
-
for (let i = 0, o = 0
|
|
103
|
+
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
97
104
|
if (seq[i] !== '-') {
|
|
98
105
|
const c = alignment[i]
|
|
99
106
|
const l = leftPx + scale * o
|
|
100
107
|
if (seq[i] === c && c !== '-' && c !== ' ') {
|
|
101
|
-
fillRect(ctx, l,
|
|
108
|
+
fillRect(ctx, l, t2, scale + f, h, canvasWidth)
|
|
102
109
|
}
|
|
103
110
|
o++
|
|
104
111
|
}
|
|
@@ -106,7 +113,7 @@ export function makeImageData({
|
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
// mismatches
|
|
109
|
-
for (let i = 0, o = 0
|
|
116
|
+
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
110
117
|
const c = alignment[i]
|
|
111
118
|
if (seq[i] !== '-') {
|
|
112
119
|
if (c !== '-') {
|
|
@@ -115,7 +122,7 @@ export function makeImageData({
|
|
|
115
122
|
fillRect(
|
|
116
123
|
ctx,
|
|
117
124
|
l,
|
|
118
|
-
|
|
125
|
+
t2,
|
|
119
126
|
scale + f,
|
|
120
127
|
h,
|
|
121
128
|
canvasWidth,
|
|
@@ -128,7 +135,7 @@ export function makeImageData({
|
|
|
128
135
|
fillRect(
|
|
129
136
|
ctx,
|
|
130
137
|
l,
|
|
131
|
-
|
|
138
|
+
t2,
|
|
132
139
|
scale + f,
|
|
133
140
|
h,
|
|
134
141
|
canvasWidth,
|
|
@@ -146,7 +153,7 @@ export function makeImageData({
|
|
|
146
153
|
// font
|
|
147
154
|
const charSizeW = 10
|
|
148
155
|
if (scale >= charSizeW) {
|
|
149
|
-
for (let i = 0, o = 0
|
|
156
|
+
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
150
157
|
if (seq[i] !== '-') {
|
|
151
158
|
const l = leftPx + scale * o
|
|
152
159
|
const offset = (scale - charSizeW) / 2 + 1
|
|
@@ -156,7 +163,11 @@ export function makeImageData({
|
|
|
156
163
|
? (contrastForBase[c] ?? 'white')
|
|
157
164
|
: 'black'
|
|
158
165
|
if (rowHeight > charHeight) {
|
|
159
|
-
ctx.fillText(
|
|
166
|
+
ctx.fillText(
|
|
167
|
+
getLetter(origAlignment[i] || '', showAsUpperCase),
|
|
168
|
+
l + offset,
|
|
169
|
+
hp2 + t + 3,
|
|
170
|
+
)
|
|
160
171
|
}
|
|
161
172
|
}
|
|
162
173
|
o++
|
|
@@ -170,11 +181,11 @@ export function makeImageData({
|
|
|
170
181
|
// insertions are always 'on top' of the other features
|
|
171
182
|
for (const feature of features.values()) {
|
|
172
183
|
const [leftPx] = featureSpanPx(feature, region, bpPerPx)
|
|
173
|
-
const vals = feature.get('alignments') as Record<string, {
|
|
184
|
+
const vals = feature.get('alignments') as Record<string, { seq: string }>
|
|
174
185
|
const seq = feature.get('seq').toLowerCase()
|
|
175
186
|
|
|
176
187
|
for (const [sample, val] of Object.entries(vals)) {
|
|
177
|
-
const origAlignment = val.
|
|
188
|
+
const origAlignment = val.seq
|
|
178
189
|
const alignment = origAlignment.toLowerCase()
|
|
179
190
|
const row = sampleToRowMap.get(sample)
|
|
180
191
|
if (row === undefined) {
|
|
@@ -182,8 +193,8 @@ export function makeImageData({
|
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
const t = rowHeight * row
|
|
185
|
-
|
|
186
|
-
for (let i = 0, o = 0
|
|
196
|
+
const t2 = offset + t
|
|
197
|
+
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
187
198
|
let ins = ''
|
|
188
199
|
while (seq[i] === '-') {
|
|
189
200
|
if (alignment[i] !== '-' && alignment[i] !== ' ') {
|
|
@@ -197,14 +208,14 @@ export function makeImageData({
|
|
|
197
208
|
if (ins.length > 10) {
|
|
198
209
|
const txt = `${ins.length}`
|
|
199
210
|
if (bpPerPx > 10) {
|
|
200
|
-
fillRect(ctx, l - 1,
|
|
211
|
+
fillRect(ctx, l - 1, t2, 2, h, canvasWidth, 'purple')
|
|
201
212
|
} else if (h > charHeight) {
|
|
202
|
-
const rwidth = measureText(txt)
|
|
203
|
-
const padding =
|
|
213
|
+
const rwidth = measureText(txt, 10)
|
|
214
|
+
const padding = 2
|
|
204
215
|
fillRect(
|
|
205
216
|
ctx,
|
|
206
217
|
l - rwidth / 2 - padding,
|
|
207
|
-
|
|
218
|
+
t2,
|
|
208
219
|
rwidth + 2 * padding,
|
|
209
220
|
h,
|
|
210
221
|
canvasWidth,
|
|
@@ -217,7 +228,7 @@ export function makeImageData({
|
|
|
217
228
|
fillRect(
|
|
218
229
|
ctx,
|
|
219
230
|
l - padding,
|
|
220
|
-
|
|
231
|
+
t2,
|
|
221
232
|
2 * padding,
|
|
222
233
|
h,
|
|
223
234
|
canvasWidth,
|
|
@@ -225,10 +236,10 @@ export function makeImageData({
|
|
|
225
236
|
)
|
|
226
237
|
}
|
|
227
238
|
} else {
|
|
228
|
-
fillRect(ctx, l,
|
|
239
|
+
fillRect(ctx, l, t2, 1, h, canvasWidth, 'purple')
|
|
229
240
|
if (bpPerPx < 0.2 && rowHeight > 5) {
|
|
230
|
-
fillRect(ctx, l - 2,
|
|
231
|
-
fillRect(ctx, l - 2,
|
|
241
|
+
fillRect(ctx, l - 2, t2, 5, 1, canvasWidth)
|
|
242
|
+
fillRect(ctx, l - 2, t2 + h - 1, 5, 1, canvasWidth)
|
|
232
243
|
}
|
|
233
244
|
}
|
|
234
245
|
}
|
|
@@ -2,7 +2,6 @@ import PluginManager from '@jbrowse/core/PluginManager'
|
|
|
2
2
|
import { AddTrackWorkflowType } from '@jbrowse/core/pluggableElementTypes'
|
|
3
3
|
import { types } from 'mobx-state-tree'
|
|
4
4
|
|
|
5
|
-
// locals
|
|
6
5
|
import MultiMAFWidget from './AddTrackWorkflow'
|
|
7
6
|
|
|
8
7
|
export default function MafAddTrackWorkflowF(pluginManager: PluginManager) {
|