@jbrowse/plugin-circular-view 1.5.6 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plugin-circular-view.cjs.development.js +1553 -1501
- package/dist/plugin-circular-view.cjs.development.js.map +1 -1
- package/dist/plugin-circular-view.cjs.production.min.js +1 -1
- package/dist/plugin-circular-view.cjs.production.min.js.map +1 -1
- package/dist/plugin-circular-view.esm.js +1562 -1510
- package/dist/plugin-circular-view.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/CircularView/components/CircularView.js +61 -70
- package/src/CircularView/components/ImportForm.tsx +29 -51
- package/src/CircularView/models/CircularView.ts +11 -15
- package/src/index.ts +44 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-circular-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "JBrowse 2 circular view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "d6ad1b8e7fbb00000f2ac87f463c82e9db12ea01"
|
|
53
53
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
|
+
import { ResizeHandle, ErrorMessage } from '@jbrowse/core/ui'
|
|
4
|
+
import { assembleLocString } from '@jbrowse/core/util'
|
|
5
|
+
import { IconButton, makeStyles } from '@material-ui/core'
|
|
6
|
+
import { grey } from '@material-ui/core/colors'
|
|
3
7
|
|
|
8
|
+
// icons
|
|
4
9
|
import ZoomOut from '@material-ui/icons/ZoomOut'
|
|
5
10
|
import ZoomIn from '@material-ui/icons/ZoomIn'
|
|
6
11
|
import RotateLeft from '@material-ui/icons/RotateLeft'
|
|
@@ -9,84 +14,70 @@ import LockOutline from '@material-ui/icons/LockOutlined'
|
|
|
9
14
|
import LockOpen from '@material-ui/icons/LockOpen'
|
|
10
15
|
import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
|
|
11
16
|
|
|
12
|
-
//
|
|
13
|
-
import { IconButton, makeStyles } from '@material-ui/core'
|
|
14
|
-
|
|
15
|
-
import { grey } from '@material-ui/core/colors'
|
|
16
|
-
|
|
17
|
-
import { ResizeHandle } from '@jbrowse/core/ui'
|
|
18
|
-
import { assembleLocString } from '@jbrowse/core/util'
|
|
17
|
+
// locals
|
|
19
18
|
import Ruler from './Ruler'
|
|
20
19
|
import ImportForm from './ImportForm'
|
|
21
20
|
|
|
22
21
|
const dragHandleHeight = 3
|
|
23
22
|
|
|
24
|
-
const useStyles = makeStyles(theme => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
})
|
|
23
|
+
const useStyles = makeStyles(theme => ({
|
|
24
|
+
root: {
|
|
25
|
+
position: 'relative',
|
|
26
|
+
marginBottom: theme.spacing(1),
|
|
27
|
+
overflow: 'hidden',
|
|
28
|
+
background: 'white',
|
|
29
|
+
},
|
|
30
|
+
scroller: {
|
|
31
|
+
overflow: 'auto',
|
|
32
|
+
},
|
|
33
|
+
sliceRoot: {
|
|
34
|
+
background: 'none',
|
|
35
|
+
// background: theme.palette.background.paper,
|
|
36
|
+
boxSizing: 'content-box',
|
|
37
|
+
display: 'block',
|
|
38
|
+
},
|
|
39
|
+
iconButton: {
|
|
40
|
+
padding: '4px',
|
|
41
|
+
margin: '0 2px 0 2px',
|
|
42
|
+
},
|
|
43
|
+
controls: {
|
|
44
|
+
overflow: 'hidden',
|
|
45
|
+
whiteSpace: 'nowrap',
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
background: grey[200],
|
|
48
|
+
boxSizing: 'border-box',
|
|
49
|
+
borderRight: '1px solid #a2a2a2',
|
|
50
|
+
borderBottom: '1px solid #a2a2a2',
|
|
51
|
+
left: 0,
|
|
52
|
+
top: 0,
|
|
53
|
+
},
|
|
54
|
+
importFormContainer: {
|
|
55
|
+
marginBottom: theme.spacing(4),
|
|
56
|
+
},
|
|
57
|
+
}))
|
|
61
58
|
|
|
62
59
|
const Slices = observer(({ model }) => {
|
|
63
60
|
return (
|
|
64
61
|
<>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
display={display}
|
|
85
|
-
view={model}
|
|
86
|
-
/>
|
|
87
|
-
)
|
|
88
|
-
})}
|
|
89
|
-
</>
|
|
62
|
+
{model.staticSlices.map(slice => (
|
|
63
|
+
<Ruler
|
|
64
|
+
key={assembleLocString(
|
|
65
|
+
slice.region.elided ? slice.region.regions[0] : slice.region,
|
|
66
|
+
)}
|
|
67
|
+
model={model}
|
|
68
|
+
slice={slice}
|
|
69
|
+
/>
|
|
70
|
+
))}
|
|
71
|
+
{model.tracks.map(track => {
|
|
72
|
+
const display = track.displays[0]
|
|
73
|
+
return (
|
|
74
|
+
<display.RenderingComponent
|
|
75
|
+
key={display.id}
|
|
76
|
+
display={display}
|
|
77
|
+
view={model}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
})}
|
|
90
81
|
</>
|
|
91
82
|
)
|
|
92
83
|
})
|
|
@@ -183,7 +174,7 @@ const CircularView = observer(({ model }) => {
|
|
|
183
174
|
data-testid={model.id}
|
|
184
175
|
>
|
|
185
176
|
{model.error ? (
|
|
186
|
-
<
|
|
177
|
+
<ErrorMessage error={model.error} />
|
|
187
178
|
) : (
|
|
188
179
|
<>
|
|
189
180
|
{showImportForm ? <ImportForm model={model} /> : null}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
+
import { Button, Container, Grid, makeStyles } from '@material-ui/core'
|
|
2
3
|
import { observer } from 'mobx-react'
|
|
3
4
|
import { getSession } from '@jbrowse/core/util'
|
|
4
|
-
|
|
5
|
-
// material-ui stuff
|
|
6
|
-
import {
|
|
7
|
-
Button,
|
|
8
|
-
Container,
|
|
9
|
-
Grid,
|
|
10
|
-
Typography,
|
|
11
|
-
makeStyles,
|
|
12
|
-
} from '@material-ui/core'
|
|
5
|
+
import ErrorMessage from '@jbrowse/core/ui/ErrorMessage'
|
|
13
6
|
import AssemblySelector from '@jbrowse/core/ui/AssemblySelector'
|
|
14
7
|
|
|
15
8
|
const useStyles = makeStyles(theme => ({
|
|
@@ -18,14 +11,6 @@ const useStyles = makeStyles(theme => ({
|
|
|
18
11
|
},
|
|
19
12
|
}))
|
|
20
13
|
|
|
21
|
-
const ErrorDisplay = observer(({ error }: { error?: Error | string }) => {
|
|
22
|
-
return (
|
|
23
|
-
<Typography variant="h6" color="error">
|
|
24
|
-
{`${error}`}
|
|
25
|
-
</Typography>
|
|
26
|
-
)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
15
|
const ImportForm = observer(({ model }: { model: any }) => {
|
|
31
16
|
const classes = useStyles()
|
|
@@ -42,45 +27,38 @@ const ImportForm = observer(({ model }: { model: any }) => {
|
|
|
42
27
|
const err = assemblyError || error
|
|
43
28
|
|
|
44
29
|
return (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{err ? (
|
|
48
|
-
<Grid
|
|
49
|
-
container
|
|
50
|
-
spacing={1}
|
|
51
|
-
justifyContent="center"
|
|
52
|
-
alignItems="center"
|
|
53
|
-
>
|
|
54
|
-
<Grid item>
|
|
55
|
-
<ErrorDisplay error={err} />
|
|
56
|
-
</Grid>
|
|
57
|
-
</Grid>
|
|
58
|
-
) : null}
|
|
30
|
+
<Container className={classes.importFormContainer}>
|
|
31
|
+
{err ? (
|
|
59
32
|
<Grid container spacing={1} justifyContent="center" alignItems="center">
|
|
60
33
|
<Grid item>
|
|
61
|
-
<
|
|
62
|
-
onChange={val => {
|
|
63
|
-
setError(undefined)
|
|
64
|
-
setSelectedAsm(val)
|
|
65
|
-
}}
|
|
66
|
-
session={session}
|
|
67
|
-
selected={selectedAsm}
|
|
68
|
-
/>
|
|
34
|
+
<ErrorMessage error={err} />
|
|
69
35
|
</Grid>
|
|
36
|
+
</Grid>
|
|
37
|
+
) : null}
|
|
38
|
+
<Grid container spacing={1} justifyContent="center" alignItems="center">
|
|
39
|
+
<Grid item>
|
|
40
|
+
<AssemblySelector
|
|
41
|
+
onChange={val => {
|
|
42
|
+
setError(undefined)
|
|
43
|
+
setSelectedAsm(val)
|
|
44
|
+
}}
|
|
45
|
+
session={session}
|
|
46
|
+
selected={selectedAsm}
|
|
47
|
+
/>
|
|
48
|
+
</Grid>
|
|
70
49
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</Grid>
|
|
50
|
+
<Grid item>
|
|
51
|
+
<Button
|
|
52
|
+
disabled={!regions?.length}
|
|
53
|
+
onClick={() => model.setDisplayedRegions(regions)}
|
|
54
|
+
variant="contained"
|
|
55
|
+
color="primary"
|
|
56
|
+
>
|
|
57
|
+
{regions.length ? 'Open' : 'Loading…'}
|
|
58
|
+
</Button>
|
|
81
59
|
</Grid>
|
|
82
|
-
</
|
|
83
|
-
|
|
60
|
+
</Grid>
|
|
61
|
+
</Container>
|
|
84
62
|
)
|
|
85
63
|
})
|
|
86
64
|
|
|
@@ -58,7 +58,7 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
58
58
|
trackSelectorType: 'hierarchical',
|
|
59
59
|
})
|
|
60
60
|
.volatile(() => ({
|
|
61
|
-
width:
|
|
61
|
+
width: 0,
|
|
62
62
|
}))
|
|
63
63
|
.views(self => ({
|
|
64
64
|
get staticSlices() {
|
|
@@ -203,20 +203,16 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
203
203
|
// it to be loaded. this is done by looking in the assemblyManager's
|
|
204
204
|
// assembly list, and then waiting on it's initialized state which is
|
|
205
205
|
// updated later
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
},
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
return assembliesInitialized
|
|
206
|
+
return this.assemblyNames.every(assemblyName => {
|
|
207
|
+
if (
|
|
208
|
+
assemblyManager.assemblyList
|
|
209
|
+
?.map(asm => asm.name)
|
|
210
|
+
.includes(assemblyName)
|
|
211
|
+
) {
|
|
212
|
+
return assemblyManager.get(assemblyName)?.initialized
|
|
213
|
+
}
|
|
214
|
+
return true
|
|
215
|
+
})
|
|
220
216
|
},
|
|
221
217
|
}))
|
|
222
218
|
.volatile(() => ({
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { lazy } from 'react'
|
|
2
|
+
import { when } from 'mobx'
|
|
2
3
|
import { AbstractSessionModel, isAbstractMenuManager } from '@jbrowse/core/util'
|
|
3
4
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
4
5
|
import Plugin from '@jbrowse/core/Plugin'
|
|
5
6
|
import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'
|
|
6
7
|
import DataUsageIcon from '@material-ui/icons/DataUsage'
|
|
7
|
-
import stateModelFactory
|
|
8
|
+
import stateModelFactory, {
|
|
9
|
+
CircularViewModel,
|
|
10
|
+
} from './CircularView/models/CircularView'
|
|
11
|
+
|
|
12
|
+
type CGV = CircularViewModel
|
|
8
13
|
|
|
9
14
|
export default class CircularViewPlugin extends Plugin {
|
|
10
15
|
name = 'CircularViewPlugin'
|
|
@@ -20,6 +25,44 @@ export default class CircularViewPlugin extends Plugin {
|
|
|
20
25
|
name: 'CircularView',
|
|
21
26
|
}),
|
|
22
27
|
)
|
|
28
|
+
|
|
29
|
+
pluginManager.addToExtensionPoint(
|
|
30
|
+
'LaunchView-CircularView',
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
async ({
|
|
33
|
+
session,
|
|
34
|
+
assembly,
|
|
35
|
+
loc,
|
|
36
|
+
tracks = [],
|
|
37
|
+
}: {
|
|
38
|
+
session: AbstractSessionModel
|
|
39
|
+
assembly?: string
|
|
40
|
+
loc: string
|
|
41
|
+
tracks?: string[]
|
|
42
|
+
}) => {
|
|
43
|
+
const { assemblyManager } = session
|
|
44
|
+
const view = session.addView('CircularView', {}) as CGV
|
|
45
|
+
|
|
46
|
+
await when(() => view.initialized)
|
|
47
|
+
|
|
48
|
+
if (!assembly) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
'No assembly provided when launching circular genome view',
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const asm = await assemblyManager.waitForAssembly(assembly)
|
|
55
|
+
if (!asm) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Assembly "${assembly}" not found when launching circular genome view`,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
view.setDisplayedRegions(asm.regions || [])
|
|
62
|
+
|
|
63
|
+
tracks.forEach(track => view.showTrack(track))
|
|
64
|
+
},
|
|
65
|
+
)
|
|
23
66
|
}
|
|
24
67
|
|
|
25
68
|
configure(pluginManager: PluginManager) {
|