jbrowse-plugin-mafviewer 1.0.5 → 1.0.8
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/CHANGELOG.md +4 -0
- package/README.md +17 -2
- package/dist/BigMafAdapter/BigMafAdapter.d.ts +17 -0
- package/dist/BigMafAdapter/BigMafAdapter.js +92 -0
- package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -0
- package/dist/BigMafAdapter/configSchema.d.ts +21 -0
- package/dist/BigMafAdapter/configSchema.js +28 -0
- package/dist/BigMafAdapter/configSchema.js.map +1 -0
- package/dist/BigMafAdapter/index.d.ts +2 -0
- package/dist/BigMafAdapter/index.js +11 -0
- package/dist/BigMafAdapter/index.js.map +1 -0
- package/dist/LinearMafDisplay/components/ColorLegend.d.ts +8 -0
- package/dist/LinearMafDisplay/components/ColorLegend.js +15 -0
- package/dist/LinearMafDisplay/components/ColorLegend.js.map +1 -0
- package/dist/LinearMafDisplay/components/ReactComponent.d.ts +6 -0
- package/dist/LinearMafDisplay/components/ReactComponent.js +15 -0
- package/dist/LinearMafDisplay/components/ReactComponent.js.map +1 -0
- package/dist/LinearMafDisplay/components/RectBg.d.ts +9 -0
- package/dist/LinearMafDisplay/components/RectBg.js +7 -0
- package/dist/LinearMafDisplay/components/RectBg.js.map +1 -0
- package/dist/LinearMafDisplay/components/SetRowHeight.d.ts +11 -0
- package/dist/LinearMafDisplay/components/SetRowHeight.js +36 -0
- package/dist/LinearMafDisplay/components/SetRowHeight.js.map +1 -0
- package/dist/LinearMafDisplay/components/YScaleBars.d.ts +9 -0
- package/dist/LinearMafDisplay/components/YScaleBars.js +41 -0
- package/dist/LinearMafDisplay/components/YScaleBars.js.map +1 -0
- package/dist/LinearMafDisplay/configSchema.d.ts +34 -0
- package/dist/LinearMafDisplay/configSchema.js +15 -0
- package/dist/LinearMafDisplay/configSchema.js.map +1 -0
- package/dist/LinearMafDisplay/index.d.ts +2 -0
- package/dist/LinearMafDisplay/index.js +20 -0
- package/dist/LinearMafDisplay/index.js.map +1 -0
- package/dist/LinearMafDisplay/renderSvg.d.ts +4 -0
- package/dist/LinearMafDisplay/renderSvg.js +17 -0
- package/dist/LinearMafDisplay/renderSvg.js.map +1 -0
- package/dist/LinearMafDisplay/stateModel.d.ts +364 -0
- package/dist/LinearMafDisplay/stateModel.js +176 -0
- package/dist/LinearMafDisplay/stateModel.js.map +1 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +45 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.js +181 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -0
- package/dist/LinearMafRenderer/components/ReactComponent.d.ts +6 -0
- package/dist/LinearMafRenderer/components/ReactComponent.js +8 -0
- package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -0
- package/dist/LinearMafRenderer/configSchema.d.ts +2 -0
- package/dist/LinearMafRenderer/configSchema.js +13 -0
- package/dist/LinearMafRenderer/configSchema.js.map +1 -0
- package/dist/LinearMafRenderer/index.d.ts +2 -0
- package/dist/LinearMafRenderer/index.js +12 -0
- package/dist/LinearMafRenderer/index.js.map +1 -0
- package/dist/LinearMafRenderer/util.d.ts +10 -0
- package/dist/LinearMafRenderer/util.js +16 -0
- package/dist/LinearMafRenderer/util.js.map +1 -0
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.d.ts +5 -0
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +111 -0
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -0
- package/dist/MafAddTrackWorkflow/index.d.ts +2 -0
- package/dist/MafAddTrackWorkflow/index.js +12 -0
- package/dist/MafAddTrackWorkflow/index.js.map +1 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +17 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.js +96 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -0
- package/dist/MafTabixAdapter/configSchema.d.ts +33 -0
- package/dist/MafTabixAdapter/configSchema.js +40 -0
- package/dist/MafTabixAdapter/configSchema.js.map +1 -0
- package/dist/MafTabixAdapter/index.d.ts +2 -0
- package/dist/MafTabixAdapter/index.js +11 -0
- package/dist/MafTabixAdapter/index.js.map +1 -0
- package/dist/MafTrack/configSchema.d.ts +79 -0
- package/dist/MafTrack/configSchema.js +15 -0
- package/dist/MafTrack/configSchema.js.map +1 -0
- package/dist/MafTrack/index.d.ts +2 -0
- package/dist/MafTrack/index.js +14 -0
- package/dist/MafTrack/index.js.map +1 -0
- package/dist/TaffyAdapter/TaffyAdapter.d.ts +16 -0
- package/dist/TaffyAdapter/TaffyAdapter.js +89 -0
- package/dist/TaffyAdapter/TaffyAdapter.js.map +1 -0
- package/dist/TaffyAdapter/configSchema.d.ts +31 -0
- package/dist/TaffyAdapter/configSchema.js +38 -0
- package/dist/TaffyAdapter/configSchema.js.map +1 -0
- package/dist/TaffyAdapter/index.d.ts +2 -0
- package/dist/TaffyAdapter/index.js +11 -0
- package/dist/TaffyAdapter/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +4 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +7 -1
- package/package.json +22 -51
- package/src/BigMafAdapter/BigMafAdapter.ts +1 -2
- package/src/LinearMafDisplay/components/ColorLegend.tsx +2 -2
- package/src/LinearMafDisplay/components/SetRowHeight.tsx +9 -3
- package/src/LinearMafDisplay/components/YScaleBars.tsx +11 -3
- package/src/LinearMafDisplay/stateModel.ts +29 -1
- package/src/LinearMafRenderer/LinearMafRenderer.ts +38 -34
- package/src/LinearMafRenderer/util.ts +20 -0
- package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +60 -22
- package/src/MafTabixAdapter/MafTabixAdapter.ts +27 -10
- package/src/TaffyAdapter/TaffyAdapter.ts +112 -0
- package/src/TaffyAdapter/configSchema.ts +44 -0
- package/src/TaffyAdapter/index.ts +15 -0
- package/src/index.ts +2 -0
- package/dist/jbrowse-plugin-mafviewer.umd.development.js +0 -1423
- package/dist/jbrowse-plugin-mafviewer.umd.development.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.0.8",
|
|
3
3
|
"name": "jbrowse-plugin-mafviewer",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"jbrowse",
|
|
@@ -12,77 +12,48 @@
|
|
|
12
12
|
"dist",
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
|
-
"config": {
|
|
16
|
-
"port": 9000,
|
|
17
|
-
"browse": {
|
|
18
|
-
"port": 8999
|
|
19
|
-
},
|
|
20
|
-
"jbrowse": {
|
|
21
|
-
"plugin": {
|
|
22
|
-
"name": "MafViewer"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
15
|
"scripts": {
|
|
27
16
|
"clean": "rimraf dist",
|
|
28
17
|
"start": "node esbuild.mjs",
|
|
29
18
|
"prebuild": "npm run clean",
|
|
30
|
-
"build": "
|
|
31
|
-
"lint": "eslint --
|
|
19
|
+
"build": "tsc && NODE_ENV=production node esbuild.mjs",
|
|
20
|
+
"lint": "eslint --report-unused-disable-directives --max-warnings 0",
|
|
32
21
|
"prepack": "npm run build",
|
|
33
22
|
"postversion": "git push --follow-tags"
|
|
34
23
|
},
|
|
35
|
-
"jbrowse-plugin": {
|
|
36
|
-
"name": "MafViewer"
|
|
37
|
-
},
|
|
38
24
|
"devDependencies": {
|
|
39
25
|
"@babel/core": "^7.16.5",
|
|
40
26
|
"@babel/preset-react": "^7.10.4",
|
|
41
27
|
"@emotion/react": "^11.10.4",
|
|
42
28
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
|
43
|
-
"@jbrowse/cli": "^2.6.1",
|
|
44
29
|
"@jbrowse/core": "^2.6.1",
|
|
45
|
-
"@jbrowse/development-tools": "^2.1.1",
|
|
46
30
|
"@jbrowse/plugin-data-management": "^2.7.1",
|
|
47
31
|
"@jbrowse/plugin-linear-genome-view": "^2.7.1",
|
|
48
|
-
"@mui/material": "^
|
|
49
|
-
"@mui/system": "^
|
|
50
|
-
"@mui/x-data-grid": "^
|
|
51
|
-
"@
|
|
52
|
-
"@types/
|
|
53
|
-
"@
|
|
54
|
-
"@typescript-eslint/
|
|
55
|
-
"@typescript-eslint/parser": "^6.8.0",
|
|
56
|
-
"babel-eslint": "^10.0.0",
|
|
32
|
+
"@mui/material": "^6.2.0",
|
|
33
|
+
"@mui/system": "^6.2.0",
|
|
34
|
+
"@mui/x-data-grid": "^7.2.0",
|
|
35
|
+
"@types/node": "^22.10.2",
|
|
36
|
+
"@types/react": "^19.0.1",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
38
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
57
39
|
"chalk": "^5.3.0",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"cypress": "^13.3.2",
|
|
61
|
-
"esbuild": "^0.19.5",
|
|
62
|
-
"eslint": "^8.36.0",
|
|
63
|
-
"eslint-config-prettier": "^9.0.0",
|
|
64
|
-
"eslint-config-react-app": "^7.0.1",
|
|
65
|
-
"eslint-plugin-flowtype": "^8.0.3",
|
|
66
|
-
"eslint-plugin-import": "^2.22.0",
|
|
67
|
-
"eslint-plugin-jsx-a11y": "^6.3.1",
|
|
68
|
-
"eslint-plugin-prettier": "^5.0.1",
|
|
40
|
+
"esbuild": "^0.24.0",
|
|
41
|
+
"eslint": "^9.17.0",
|
|
69
42
|
"eslint-plugin-react": "^7.20.3",
|
|
70
|
-
"eslint-plugin-react-hooks": "^
|
|
71
|
-
"eslint-plugin-
|
|
72
|
-
"eslint-plugin-unicorn": "^48.0.1",
|
|
43
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
44
|
+
"eslint-plugin-unicorn": "^56.0.1",
|
|
73
45
|
"mobx": "^6.0.0",
|
|
74
46
|
"mobx-react": "^9.0.1",
|
|
75
|
-
"mobx-state-tree": "5.
|
|
76
|
-
"prettier": "^3.
|
|
77
|
-
"
|
|
78
|
-
"react": "^
|
|
79
|
-
"react-dom": "^
|
|
80
|
-
"rimraf": "^
|
|
81
|
-
"rollup": "^3.0.0",
|
|
47
|
+
"mobx-state-tree": "5.4.1",
|
|
48
|
+
"prettier": "^3.4.2",
|
|
49
|
+
"pretty-bytes": "^6.1.1",
|
|
50
|
+
"react": "^19.0.0",
|
|
51
|
+
"react-dom": "^19.0.0",
|
|
52
|
+
"rimraf": "^6.0.1",
|
|
82
53
|
"rxjs": "^7.8.1",
|
|
83
54
|
"serve": "^14.2.0",
|
|
84
|
-
"start-server-and-test": "^2.0.0",
|
|
85
55
|
"tss-react": "^4.8.6",
|
|
86
|
-
"typescript": "^5.1.6"
|
|
56
|
+
"typescript": "^5.1.6",
|
|
57
|
+
"typescript-eslint": "^8.18.0"
|
|
87
58
|
}
|
|
88
59
|
}
|
|
@@ -29,7 +29,7 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
|
|
|
29
29
|
}
|
|
30
30
|
async setupPre() {
|
|
31
31
|
if (!this.setupP) {
|
|
32
|
-
this.setupP = this.setup().catch(e => {
|
|
32
|
+
this.setupP = this.setup().catch((e: unknown) => {
|
|
33
33
|
this.setupP = undefined
|
|
34
34
|
throw e
|
|
35
35
|
})
|
|
@@ -73,7 +73,6 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// eslint-disable-next-line unicorn/no-for-loop
|
|
77
76
|
for (let i = 0; i < blocks2.length; i++) {
|
|
78
77
|
const elt = blocks2[i]
|
|
79
78
|
const ad = elt.split(/ +/)
|
|
@@ -18,7 +18,7 @@ const ColorLegend = observer(function ({
|
|
|
18
18
|
const canDisplayLabel = rowHeight >= 10
|
|
19
19
|
const boxHeight = Math.min(20, rowHeight)
|
|
20
20
|
|
|
21
|
-
return
|
|
21
|
+
return (
|
|
22
22
|
<>
|
|
23
23
|
{samples.map((sample, idx) => (
|
|
24
24
|
<RectBg
|
|
@@ -44,7 +44,7 @@ const ColorLegend = observer(function ({
|
|
|
44
44
|
))
|
|
45
45
|
: null}
|
|
46
46
|
</>
|
|
47
|
-
)
|
|
47
|
+
)
|
|
48
48
|
})
|
|
49
49
|
|
|
50
50
|
export default ColorLegend
|
|
@@ -39,12 +39,16 @@ const SetRowHeightDialog = observer(function (props: {
|
|
|
39
39
|
</Typography>
|
|
40
40
|
<TextField
|
|
41
41
|
value={rowHeight}
|
|
42
|
-
onChange={event =>
|
|
42
|
+
onChange={event => {
|
|
43
|
+
setRowHeight(event.target.value)
|
|
44
|
+
}}
|
|
43
45
|
placeholder="Enter row height"
|
|
44
46
|
/>
|
|
45
47
|
<TextField
|
|
46
48
|
value={rowProportion}
|
|
47
|
-
onChange={event =>
|
|
49
|
+
onChange={event => {
|
|
50
|
+
setRowProportion(event.target.value)
|
|
51
|
+
}}
|
|
48
52
|
placeholder="Enter row proportion"
|
|
49
53
|
/>
|
|
50
54
|
<DialogActions>
|
|
@@ -64,7 +68,9 @@ const SetRowHeightDialog = observer(function (props: {
|
|
|
64
68
|
<Button
|
|
65
69
|
variant="contained"
|
|
66
70
|
color="secondary"
|
|
67
|
-
onClick={() =>
|
|
71
|
+
onClick={() => {
|
|
72
|
+
handleClose()
|
|
73
|
+
}}
|
|
68
74
|
>
|
|
69
75
|
Cancel
|
|
70
76
|
</Button>
|
|
@@ -36,6 +36,14 @@ const Wrapper = observer(function ({
|
|
|
36
36
|
}
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
+
export function max(arr: number[], init = Number.NEGATIVE_INFINITY) {
|
|
40
|
+
let max = init
|
|
41
|
+
for (const entry of arr) {
|
|
42
|
+
max = Math.max(entry, max)
|
|
43
|
+
}
|
|
44
|
+
return max
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
export const YScaleBars = observer(function (props: {
|
|
40
48
|
model: LinearMafDisplayModel
|
|
41
49
|
orientation?: string
|
|
@@ -47,10 +55,10 @@ export const YScaleBars = observer(function (props: {
|
|
|
47
55
|
const canDisplayLabel = rowHeight >= 10
|
|
48
56
|
const minWidth = 20
|
|
49
57
|
|
|
50
|
-
const labelWidth =
|
|
51
|
-
|
|
58
|
+
const labelWidth = max(
|
|
59
|
+
samples
|
|
52
60
|
.map(s => measureText(s.label, svgFontSize))
|
|
53
|
-
.map(width => (canDisplayLabel ? width : minWidth))
|
|
61
|
+
.map(width => (canDisplayLabel ? width : minWidth)),
|
|
54
62
|
)
|
|
55
63
|
|
|
56
64
|
return (
|
|
@@ -52,9 +52,16 @@ export default function stateModelFactory(
|
|
|
52
52
|
* #property
|
|
53
53
|
*/
|
|
54
54
|
showAllLetters: false,
|
|
55
|
+
/**
|
|
56
|
+
* #property
|
|
57
|
+
*/
|
|
58
|
+
mismatchRendering: true,
|
|
55
59
|
}),
|
|
56
60
|
)
|
|
57
61
|
.volatile(() => ({
|
|
62
|
+
/**
|
|
63
|
+
* #volatile
|
|
64
|
+
*/
|
|
58
65
|
prefersOffset: true,
|
|
59
66
|
}))
|
|
60
67
|
.actions(self => ({
|
|
@@ -76,6 +83,12 @@ export default function stateModelFactory(
|
|
|
76
83
|
setShowAllLetters(f: boolean) {
|
|
77
84
|
self.showAllLetters = f
|
|
78
85
|
},
|
|
86
|
+
/**
|
|
87
|
+
* #action
|
|
88
|
+
*/
|
|
89
|
+
setMismatchRendering(f: boolean) {
|
|
90
|
+
self.mismatchRendering = f
|
|
91
|
+
},
|
|
79
92
|
}))
|
|
80
93
|
.views(self => ({
|
|
81
94
|
/**
|
|
@@ -114,7 +127,9 @@ export default function stateModelFactory(
|
|
|
114
127
|
}))
|
|
115
128
|
.views(self => {
|
|
116
129
|
const {
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
117
131
|
trackMenuItems: superTrackMenuItems,
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
118
133
|
renderProps: superRenderProps,
|
|
119
134
|
} = self
|
|
120
135
|
return {
|
|
@@ -128,6 +143,7 @@ export default function stateModelFactory(
|
|
|
128
143
|
samples,
|
|
129
144
|
rowHeight,
|
|
130
145
|
rowProportion,
|
|
146
|
+
mismatchRendering,
|
|
131
147
|
} = self
|
|
132
148
|
return {
|
|
133
149
|
...superRenderProps(),
|
|
@@ -136,6 +152,7 @@ export default function stateModelFactory(
|
|
|
136
152
|
rowHeight,
|
|
137
153
|
rowProportion,
|
|
138
154
|
showAllLetters,
|
|
155
|
+
mismatchRendering,
|
|
139
156
|
}
|
|
140
157
|
},
|
|
141
158
|
/**
|
|
@@ -149,7 +166,10 @@ export default function stateModelFactory(
|
|
|
149
166
|
onClick: () => {
|
|
150
167
|
getSession(self).queueDialog(handleClose => [
|
|
151
168
|
SetRowHeightDialog,
|
|
152
|
-
{
|
|
169
|
+
{
|
|
170
|
+
model: self,
|
|
171
|
+
handleClose,
|
|
172
|
+
},
|
|
153
173
|
])
|
|
154
174
|
},
|
|
155
175
|
},
|
|
@@ -161,6 +181,14 @@ export default function stateModelFactory(
|
|
|
161
181
|
self.setShowAllLetters(!self.showAllLetters)
|
|
162
182
|
},
|
|
163
183
|
},
|
|
184
|
+
{
|
|
185
|
+
label: 'Draw mismatches as single color',
|
|
186
|
+
type: 'checkbox',
|
|
187
|
+
checked: !self.mismatchRendering,
|
|
188
|
+
onClick: () => {
|
|
189
|
+
self.setMismatchRendering(!self.mismatchRendering)
|
|
190
|
+
},
|
|
191
|
+
},
|
|
164
192
|
]
|
|
165
193
|
},
|
|
166
194
|
}
|
|
@@ -7,33 +7,20 @@ import {
|
|
|
7
7
|
featureSpanPx,
|
|
8
8
|
renderToAbstractCanvas,
|
|
9
9
|
} from '@jbrowse/core/util'
|
|
10
|
-
import {
|
|
10
|
+
import { getColorBaseMap, getContrastBaseMap } from './util'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
key,
|
|
16
|
-
theme.palette.getContrastText(value),
|
|
17
|
-
]),
|
|
18
|
-
)
|
|
12
|
+
interface Sample {
|
|
13
|
+
id: string
|
|
14
|
+
color?: string
|
|
19
15
|
}
|
|
20
|
-
|
|
21
16
|
interface RenderArgs extends RenderArgsDeserialized {
|
|
22
|
-
samples:
|
|
17
|
+
samples: Sample[]
|
|
23
18
|
rowHeight: number
|
|
24
19
|
rowProportion: number
|
|
25
20
|
showAllLetters: boolean
|
|
21
|
+
mismatchRendering: boolean
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
export function getColorBaseMap(theme: Theme) {
|
|
29
|
-
const { bases } = theme.palette
|
|
30
|
-
return {
|
|
31
|
-
a: bases.A.main,
|
|
32
|
-
c: bases.C.main,
|
|
33
|
-
g: bases.G.main,
|
|
34
|
-
t: bases.T.main,
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
24
|
function makeImageData({
|
|
38
25
|
ctx,
|
|
39
26
|
renderArgs,
|
|
@@ -47,6 +34,7 @@ function makeImageData({
|
|
|
47
34
|
rowHeight,
|
|
48
35
|
showAllLetters,
|
|
49
36
|
theme: configTheme,
|
|
37
|
+
mismatchRendering,
|
|
50
38
|
samples,
|
|
51
39
|
rowProportion,
|
|
52
40
|
features,
|
|
@@ -117,23 +105,33 @@ function makeImageData({
|
|
|
117
105
|
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
118
106
|
const c = alignment[i]
|
|
119
107
|
if (seq[i] !== '-') {
|
|
120
|
-
if (
|
|
108
|
+
if (c !== '-') {
|
|
121
109
|
const l = leftPx + scale * o
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
110
|
+
if (seq[i] !== c) {
|
|
111
|
+
ctx.fillStyle = mismatchRendering
|
|
112
|
+
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
113
|
+
(colorForBase[c as keyof typeof colorForBase] ?? 'black')
|
|
114
|
+
: 'orange'
|
|
115
|
+
ctx.fillRect(l, offset + t, scale + f, h)
|
|
116
|
+
} else if (showAllLetters) {
|
|
117
|
+
ctx.fillStyle = mismatchRendering
|
|
118
|
+
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
119
|
+
(colorForBase[c as keyof typeof colorForBase] ?? 'black')
|
|
120
|
+
: 'lightblue'
|
|
121
|
+
ctx.fillRect(l, offset + t, scale + f, h)
|
|
122
|
+
}
|
|
125
123
|
}
|
|
126
124
|
o++
|
|
127
125
|
}
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
// font
|
|
131
|
-
const
|
|
132
|
-
if (scale >=
|
|
129
|
+
const charSizeW = 10
|
|
130
|
+
if (scale >= charSizeW) {
|
|
133
131
|
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
134
132
|
if (seq[i] !== '-') {
|
|
135
133
|
const l = leftPx + scale * o
|
|
136
|
-
const offset = (scale -
|
|
134
|
+
const offset = (scale - charSizeW) / 2 + 1
|
|
137
135
|
const c = alignment[i]
|
|
138
136
|
if ((showAllLetters || seq[i] !== c) && c !== '-') {
|
|
139
137
|
ctx.fillStyle = contrastForBase[c] ?? 'white'
|
|
@@ -203,14 +201,20 @@ export default class LinearMafRenderer extends FeatureRendererType {
|
|
|
203
201
|
const height = samples.length * rowHeight + 100
|
|
204
202
|
const width = (region.end - region.start) / bpPerPx
|
|
205
203
|
const features = await this.getFeatures(renderProps)
|
|
206
|
-
const res = await renderToAbstractCanvas(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
204
|
+
const res = await renderToAbstractCanvas(
|
|
205
|
+
width,
|
|
206
|
+
height,
|
|
207
|
+
renderProps,
|
|
208
|
+
ctx => {
|
|
209
|
+
makeImageData({
|
|
210
|
+
ctx,
|
|
211
|
+
renderArgs: {
|
|
212
|
+
...renderProps,
|
|
213
|
+
features,
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
return undefined
|
|
217
|
+
},
|
|
214
218
|
)
|
|
215
219
|
const results = await super.render({
|
|
216
220
|
...renderProps,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Theme } from '@mui/material'
|
|
2
|
+
|
|
3
|
+
export function getContrastBaseMap(theme: Theme) {
|
|
4
|
+
return Object.fromEntries(
|
|
5
|
+
Object.entries(getColorBaseMap(theme)).map(([key, value]) => [
|
|
6
|
+
key,
|
|
7
|
+
theme.palette.getContrastText(value),
|
|
8
|
+
]),
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getColorBaseMap(theme: Theme) {
|
|
13
|
+
const { bases } = theme.palette
|
|
14
|
+
return {
|
|
15
|
+
a: bases.A.main,
|
|
16
|
+
c: bases.C.main,
|
|
17
|
+
g: bases.G.main,
|
|
18
|
+
t: bases.T.main,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -42,8 +42,9 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
42
42
|
const [indexLoc, setIndexLoc] = useState<FileLocation>()
|
|
43
43
|
const [error, setError] = useState<unknown>()
|
|
44
44
|
const [trackName, setTrackName] = useState('MAF track')
|
|
45
|
-
const [
|
|
46
|
-
|
|
45
|
+
const [fileTypeChoice, setFileTypeChoice] = useState('BigMafAdapter')
|
|
46
|
+
const [indexTypeChoice, setIndexTypeChoice] = useState('TBI')
|
|
47
|
+
|
|
47
48
|
const rootModel = getRoot<any>(model)
|
|
48
49
|
return (
|
|
49
50
|
<Paper className={classes.paper}>
|
|
@@ -52,42 +53,72 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
52
53
|
<FormControl>
|
|
53
54
|
<FormLabel>File type</FormLabel>
|
|
54
55
|
<RadioGroup
|
|
55
|
-
value={
|
|
56
|
-
onChange={event =>
|
|
56
|
+
value={fileTypeChoice}
|
|
57
|
+
onChange={event => {
|
|
58
|
+
setFileTypeChoice(event.target.value)
|
|
59
|
+
}}
|
|
57
60
|
>
|
|
58
61
|
<FormControlLabel
|
|
59
62
|
value="BigMafAdapter"
|
|
60
63
|
control={<Radio />}
|
|
61
|
-
checked={
|
|
64
|
+
checked={fileTypeChoice === 'BigMafAdapter'}
|
|
62
65
|
label="bigMaf"
|
|
63
66
|
/>
|
|
64
67
|
<FormControlLabel
|
|
65
68
|
value="MafTabixAdapter"
|
|
66
69
|
control={<Radio />}
|
|
67
|
-
checked={
|
|
70
|
+
checked={fileTypeChoice === 'MafTabixAdapter'}
|
|
68
71
|
label="mafTabix"
|
|
69
72
|
/>
|
|
70
73
|
</RadioGroup>
|
|
71
74
|
</FormControl>
|
|
72
|
-
{
|
|
75
|
+
{fileTypeChoice === 'BigMafAdapter' ? (
|
|
73
76
|
<FileSelector
|
|
74
77
|
location={loc}
|
|
75
78
|
name="Path to bigMaf"
|
|
76
|
-
setLocation={arg => setLoc(arg)}
|
|
77
79
|
rootModel={rootModel}
|
|
80
|
+
setLocation={arg => {
|
|
81
|
+
setLoc(arg)
|
|
82
|
+
}}
|
|
78
83
|
/>
|
|
79
84
|
) : (
|
|
80
85
|
<>
|
|
86
|
+
<FormControl>
|
|
87
|
+
<FormLabel>Index type</FormLabel>
|
|
88
|
+
<RadioGroup
|
|
89
|
+
value={fileTypeChoice}
|
|
90
|
+
onChange={event => {
|
|
91
|
+
setIndexTypeChoice(event.target.value)
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<FormControlLabel
|
|
95
|
+
value="TBI"
|
|
96
|
+
control={<Radio />}
|
|
97
|
+
checked={indexTypeChoice === 'TBI'}
|
|
98
|
+
label="TBI"
|
|
99
|
+
/>
|
|
100
|
+
<FormControlLabel
|
|
101
|
+
value="CSI"
|
|
102
|
+
control={<Radio />}
|
|
103
|
+
checked={indexTypeChoice === 'CSI'}
|
|
104
|
+
label="CSI"
|
|
105
|
+
/>
|
|
106
|
+
</RadioGroup>
|
|
107
|
+
</FormControl>
|
|
81
108
|
<FileSelector
|
|
82
109
|
location={loc}
|
|
83
110
|
name="Path to MAF tabix"
|
|
84
|
-
setLocation={arg =>
|
|
111
|
+
setLocation={arg => {
|
|
112
|
+
setLoc(arg)
|
|
113
|
+
}}
|
|
85
114
|
rootModel={rootModel}
|
|
86
115
|
/>
|
|
87
116
|
<FileSelector
|
|
88
117
|
location={indexLoc}
|
|
89
118
|
name="Path to MAF tabix index"
|
|
90
|
-
setLocation={arg =>
|
|
119
|
+
setLocation={arg => {
|
|
120
|
+
setIndexLoc(arg)
|
|
121
|
+
}}
|
|
91
122
|
rootModel={rootModel}
|
|
92
123
|
/>
|
|
93
124
|
</>
|
|
@@ -97,7 +128,9 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
97
128
|
multiline
|
|
98
129
|
rows={10}
|
|
99
130
|
value={samples}
|
|
100
|
-
onChange={event =>
|
|
131
|
+
onChange={event => {
|
|
132
|
+
setSamples(event.target.value)
|
|
133
|
+
}}
|
|
101
134
|
placeholder={
|
|
102
135
|
'Enter sample names from the MAF file, one per line, or JSON formatted array of samples'
|
|
103
136
|
}
|
|
@@ -107,8 +140,10 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
107
140
|
|
|
108
141
|
<TextField
|
|
109
142
|
value={trackName}
|
|
110
|
-
onChange={event => setTrackName(event.target.value)}
|
|
111
143
|
helperText="Track name"
|
|
144
|
+
onChange={event => {
|
|
145
|
+
setTrackName(event.target.value)
|
|
146
|
+
}}
|
|
112
147
|
/>
|
|
113
148
|
<Button
|
|
114
149
|
variant="contained"
|
|
@@ -125,7 +160,7 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
125
160
|
|
|
126
161
|
const trackId = [
|
|
127
162
|
`${trackName.toLowerCase().replaceAll(' ', '_')}-${Date.now()}`,
|
|
128
|
-
|
|
163
|
+
session.adminMode ? '' : '-sessionTrack',
|
|
129
164
|
].join('')
|
|
130
165
|
|
|
131
166
|
if (isSessionWithAddTracks(session)) {
|
|
@@ -135,18 +170,21 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
135
170
|
name: trackName,
|
|
136
171
|
assemblyNames: [model.assembly],
|
|
137
172
|
adapter:
|
|
138
|
-
|
|
173
|
+
fileTypeChoice === 'BigMafAdapter'
|
|
139
174
|
? {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
type: fileTypeChoice,
|
|
176
|
+
bigBedLocation: loc,
|
|
177
|
+
samples: sampleNames,
|
|
178
|
+
}
|
|
144
179
|
: {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
180
|
+
type: fileTypeChoice,
|
|
181
|
+
bedGzLocation: loc,
|
|
182
|
+
index: {
|
|
183
|
+
indexType: indexTypeChoice,
|
|
184
|
+
location: indexLoc,
|
|
149
185
|
},
|
|
186
|
+
samples: sampleNames,
|
|
187
|
+
},
|
|
150
188
|
})
|
|
151
189
|
|
|
152
190
|
model.view?.showTrack(trackId)
|
|
@@ -12,7 +12,8 @@ interface OrganismRecord {
|
|
|
12
12
|
unknown: number
|
|
13
13
|
data: string
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
export default class MafTabixAdapter extends BaseFeatureDataAdapter {
|
|
16
17
|
public setupP?: Promise<{ adapter: BaseFeatureDataAdapter }>
|
|
17
18
|
|
|
18
19
|
async setup() {
|
|
@@ -30,7 +31,7 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
|
|
|
30
31
|
}
|
|
31
32
|
async setupPre() {
|
|
32
33
|
if (!this.setupP) {
|
|
33
|
-
this.setupP = this.setup().catch(e => {
|
|
34
|
+
this.setupP = this.setup().catch((e: unknown) => {
|
|
34
35
|
this.setupP = undefined
|
|
35
36
|
throw e
|
|
36
37
|
})
|
|
@@ -54,6 +55,13 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
|
|
|
54
55
|
const features = await firstValueFrom(
|
|
55
56
|
adapter.getFeatures(query).pipe(toArray()),
|
|
56
57
|
)
|
|
58
|
+
const samples = this.getConf('samples') as string[] | { id: string }[]
|
|
59
|
+
const sampleStrings =
|
|
60
|
+
typeof samples[0] === 'string'
|
|
61
|
+
? (samples as string[])
|
|
62
|
+
: (samples as { id: string }[]).map(s => s.id)
|
|
63
|
+
const sampleSet = new Set(sampleStrings)
|
|
64
|
+
let i = 0
|
|
57
65
|
for (const feature of features) {
|
|
58
66
|
const data = (feature.get('field5') as string).split(',')
|
|
59
67
|
const alignments = {} as Record<string, OrganismRecord>
|
|
@@ -64,14 +72,23 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
|
|
|
64
72
|
const idx = ad[0].lastIndexOf('.')
|
|
65
73
|
const org = ad[0].slice(0, idx)
|
|
66
74
|
const last = ad[0].slice(idx + 1)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
const s = sampleSet.has(org)
|
|
76
|
+
? org
|
|
77
|
+
: sampleStrings.find(f => ad[0].startsWith(f))
|
|
78
|
+
if (s) {
|
|
79
|
+
alignments[s] = {
|
|
80
|
+
chr: last,
|
|
81
|
+
start: +ad[1],
|
|
82
|
+
srcSize: +ad[2],
|
|
83
|
+
strand: ad[3] === '-' ? -1 : 1,
|
|
84
|
+
unknown: +ad[4],
|
|
85
|
+
data: alns[j],
|
|
86
|
+
}
|
|
87
|
+
} else if (i < 100) {
|
|
88
|
+
console.error(`line not processed ${ad[0]}`)
|
|
89
|
+
i++
|
|
90
|
+
} else if (i > 100) {
|
|
91
|
+
console.error('too many errors, not printing any more')
|
|
75
92
|
}
|
|
76
93
|
}
|
|
77
94
|
|