@jbrowse/plugin-linear-genome-view 2.4.1 → 2.5.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/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -4
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +8 -43
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
- package/dist/BaseLinearDisplay/components/TooLargeMessage.d.ts +3 -4
- package/dist/BaseLinearDisplay/components/TooLargeMessage.js +9 -9
- package/dist/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -1
- package/dist/BaseLinearDisplay/components/Tooltip.d.ts +0 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +81 -35
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +105 -143
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/dist/BaseLinearDisplay/models/configSchema.d.ts +35 -1
- package/dist/BaseLinearDisplay/models/configSchema.js +9 -0
- package/dist/BaseLinearDisplay/models/configSchema.js.map +1 -1
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js +10 -6
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
- package/dist/BaseLinearDisplay/models/util.d.ts +8 -0
- package/dist/BaseLinearDisplay/models/util.js +33 -1
- package/dist/BaseLinearDisplay/models/util.js.map +1 -1
- package/dist/BasicTrack/configSchema.d.ts +73 -1
- package/dist/FeatureTrack/configSchema.d.ts +75 -1
- package/dist/LinearBareDisplay/configSchema.d.ts +28 -1
- package/dist/LinearBareDisplay/index.js +1 -0
- package/dist/LinearBareDisplay/index.js.map +1 -1
- package/dist/LinearBareDisplay/model.d.ts +66 -23
- package/dist/LinearBareDisplay/model.js +2 -2
- package/dist/LinearBareDisplay/model.js.map +1 -1
- package/dist/LinearBasicDisplay/components/SetMaxHeight.d.ts +1 -2
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js +2 -5
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
- package/dist/LinearBasicDisplay/configSchema.d.ts +28 -1
- package/dist/LinearBasicDisplay/configSchema.js +0 -9
- package/dist/LinearBasicDisplay/configSchema.js.map +1 -1
- package/dist/LinearBasicDisplay/index.js +1 -1
- package/dist/LinearBasicDisplay/model.d.ts +76 -36
- package/dist/LinearBasicDisplay/model.js.map +1 -1
- package/dist/LinearGenomeView/components/CenterLine.d.ts +0 -1
- package/dist/LinearGenomeView/components/Cytobands.d.ts +22 -23
- package/dist/LinearGenomeView/components/ExportSvgDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/GetSequenceDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/GetSequenceDialog.js +14 -16
- package/dist/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/Gridlines.d.ts +0 -1
- package/dist/LinearGenomeView/components/Header.d.ts +0 -1
- package/dist/LinearGenomeView/components/HelpDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/ImportForm.d.ts +0 -1
- package/dist/LinearGenomeView/components/ImportForm.js +4 -7
- package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeView.d.ts +0 -1
- package/dist/LinearGenomeView/components/LinearGenomeView.js +0 -4
- package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/dist/LinearGenomeView/components/MiniControls.d.ts +0 -1
- package/dist/LinearGenomeView/components/OverviewScalebar.js +2 -1
- package/dist/LinearGenomeView/components/OverviewScalebar.js.map +1 -1
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js +53 -52
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
- package/dist/LinearGenomeView/components/RubberbandSpan.d.ts +0 -1
- package/dist/LinearGenomeView/components/SearchBox.d.ts +0 -1
- package/dist/LinearGenomeView/components/SearchResultsDialog.d.ts +5 -3
- package/dist/LinearGenomeView/components/SearchResultsDialog.js +6 -82
- package/dist/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/SearchResultsTable.d.ts +8 -0
- package/dist/LinearGenomeView/components/SearchResultsTable.js +83 -0
- package/dist/LinearGenomeView/components/SearchResultsTable.js.map +1 -0
- package/dist/LinearGenomeView/components/SequenceSearchDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/TrackContainer.d.ts +0 -1
- package/dist/LinearGenomeView/components/TrackContainer.js +8 -2
- package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/dist/LinearGenomeView/components/TracksContainer.js +5 -7
- package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/dist/LinearGenomeView/components/VerticalGuide.d.ts +0 -1
- package/dist/LinearGenomeView/components/ZoomControls.d.ts +0 -1
- package/dist/LinearGenomeView/components/util.js +1 -1
- package/dist/LinearGenomeView/components/util.js.map +1 -1
- package/dist/LinearGenomeView/model.d.ts +49 -36
- package/dist/LinearGenomeView/model.js +121 -198
- package/dist/LinearGenomeView/model.js.map +1 -1
- package/dist/LinearGenomeView/svgcomponents/SVGBackground.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGHeader.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGRegionSeparators.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGRuler.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGScalebar.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +0 -1
- package/dist/LinearGenomeView/svgcomponents/SVGTracks.d.ts +0 -1
- package/dist/LinearGenomeView/util.d.ts +29 -0
- package/dist/LinearGenomeView/util.js +79 -1
- package/dist/LinearGenomeView/util.js.map +1 -1
- package/dist/index.d.ts +201 -106
- package/esm/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -4
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +8 -20
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
- package/esm/BaseLinearDisplay/components/TooLargeMessage.d.ts +3 -4
- package/esm/BaseLinearDisplay/components/TooLargeMessage.js +9 -9
- package/esm/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -1
- package/esm/BaseLinearDisplay/components/Tooltip.d.ts +0 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +81 -35
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +105 -143
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/esm/BaseLinearDisplay/models/configSchema.d.ts +35 -1
- package/esm/BaseLinearDisplay/models/configSchema.js +9 -0
- package/esm/BaseLinearDisplay/models/configSchema.js.map +1 -1
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js +10 -6
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
- package/esm/BaseLinearDisplay/models/util.d.ts +8 -0
- package/esm/BaseLinearDisplay/models/util.js +30 -0
- package/esm/BaseLinearDisplay/models/util.js.map +1 -1
- package/esm/BasicTrack/configSchema.d.ts +73 -1
- package/esm/FeatureTrack/configSchema.d.ts +75 -1
- package/esm/LinearBareDisplay/configSchema.d.ts +28 -1
- package/esm/LinearBareDisplay/index.js +1 -0
- package/esm/LinearBareDisplay/index.js.map +1 -1
- package/esm/LinearBareDisplay/model.d.ts +66 -23
- package/esm/LinearBareDisplay/model.js +1 -1
- package/esm/LinearBareDisplay/model.js.map +1 -1
- package/esm/LinearBasicDisplay/components/SetMaxHeight.d.ts +1 -2
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js +2 -5
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
- package/esm/LinearBasicDisplay/configSchema.d.ts +28 -1
- package/esm/LinearBasicDisplay/configSchema.js +0 -9
- package/esm/LinearBasicDisplay/configSchema.js.map +1 -1
- package/esm/LinearBasicDisplay/index.js +1 -1
- package/esm/LinearBasicDisplay/model.d.ts +76 -36
- package/esm/LinearBasicDisplay/model.js.map +1 -1
- package/esm/LinearGenomeView/components/CenterLine.d.ts +0 -1
- package/esm/LinearGenomeView/components/Cytobands.d.ts +22 -23
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +0 -1
- package/esm/LinearGenomeView/components/GetSequenceDialog.d.ts +0 -1
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +15 -17
- package/esm/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/Gridlines.d.ts +0 -1
- package/esm/LinearGenomeView/components/Header.d.ts +0 -1
- package/esm/LinearGenomeView/components/HelpDialog.d.ts +0 -1
- package/esm/LinearGenomeView/components/ImportForm.d.ts +0 -1
- package/esm/LinearGenomeView/components/ImportForm.js +5 -8
- package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeView.d.ts +0 -1
- package/esm/LinearGenomeView/components/LinearGenomeView.js +0 -4
- package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/esm/LinearGenomeView/components/MiniControls.d.ts +0 -1
- package/esm/LinearGenomeView/components/OverviewScalebar.js +2 -1
- package/esm/LinearGenomeView/components/OverviewScalebar.js.map +1 -1
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js +53 -52
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
- package/esm/LinearGenomeView/components/RubberbandSpan.d.ts +0 -1
- package/esm/LinearGenomeView/components/SearchBox.d.ts +0 -1
- package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +5 -3
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -83
- package/esm/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +8 -0
- package/esm/LinearGenomeView/components/SearchResultsTable.js +77 -0
- package/esm/LinearGenomeView/components/SearchResultsTable.js.map +1 -0
- package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +0 -1
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +0 -1
- package/esm/LinearGenomeView/components/TrackContainer.js +8 -2
- package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/esm/LinearGenomeView/components/TracksContainer.js +5 -7
- package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/esm/LinearGenomeView/components/VerticalGuide.d.ts +0 -1
- package/esm/LinearGenomeView/components/ZoomControls.d.ts +0 -1
- package/esm/LinearGenomeView/components/util.js +1 -1
- package/esm/LinearGenomeView/components/util.js.map +1 -1
- package/esm/LinearGenomeView/model.d.ts +49 -36
- package/esm/LinearGenomeView/model.js +122 -199
- package/esm/LinearGenomeView/model.js.map +1 -1
- package/esm/LinearGenomeView/svgcomponents/SVGBackground.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGRuler.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGScalebar.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +0 -1
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +0 -1
- package/esm/LinearGenomeView/util.d.ts +29 -0
- package/esm/LinearGenomeView/util.js +76 -0
- package/esm/LinearGenomeView/util.js.map +1 -1
- package/esm/index.d.ts +201 -106
- package/package.json +3 -3
- package/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx +8 -28
- package/src/BaseLinearDisplay/components/TooLargeMessage.tsx +13 -11
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +148 -197
- package/src/BaseLinearDisplay/models/configSchema.ts +10 -0
- package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +19 -13
- package/src/BaseLinearDisplay/models/util.ts +43 -0
- package/src/LinearBareDisplay/index.ts +1 -0
- package/src/LinearBareDisplay/model.ts +1 -1
- package/src/LinearBasicDisplay/components/SetMaxHeight.tsx +3 -7
- package/src/LinearBasicDisplay/configSchema.ts +0 -10
- package/src/LinearBasicDisplay/index.ts +1 -1
- package/src/LinearBasicDisplay/model.ts +1 -1
- package/src/LinearGenomeView/components/GetSequenceDialog.tsx +15 -25
- package/src/LinearGenomeView/components/ImportForm.tsx +4 -14
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +0 -14
- package/src/LinearGenomeView/components/OverviewScalebar.tsx +2 -1
- package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +122 -82
- package/src/LinearGenomeView/components/SearchResultsDialog.tsx +17 -112
- package/src/LinearGenomeView/components/SearchResultsTable.tsx +121 -0
- package/src/LinearGenomeView/components/TrackContainer.tsx +12 -3
- package/src/LinearGenomeView/components/TracksContainer.tsx +9 -6
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +11 -11
- package/src/LinearGenomeView/components/util.ts +2 -1
- package/src/LinearGenomeView/index.test.ts +10 -12
- package/src/LinearGenomeView/model.ts +163 -236
- package/src/LinearGenomeView/util.ts +98 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"file-saver": "^2.0.0",
|
|
50
50
|
"material-ui-popup-state": "^5.0.0",
|
|
51
51
|
"normalize-wheel": "^1.0.1",
|
|
52
|
-
"react-error-boundary": "^
|
|
52
|
+
"react-error-boundary": "^4.0.3",
|
|
53
53
|
"react-popper": "^2.0.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"access": "public"
|
|
67
67
|
},
|
|
68
68
|
"module": "esm/index.js",
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "d1ca073996d008f0fe9a52f7c1a47ae649dcfdaf"
|
|
70
70
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
2
|
import { makeStyles } from 'tss-react/mui'
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
4
|
import { getParent } from 'mobx-state-tree'
|
|
@@ -24,34 +24,15 @@ const useStyles = makeStyles()(theme => {
|
|
|
24
24
|
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
26
|
const LoadingMessage = observer(({ model }: { model: any }) => {
|
|
27
|
-
// only show the loading message after 300ms to prevent excessive flickering
|
|
28
|
-
const [shown, setShown] = useState(false)
|
|
29
27
|
const { classes } = useStyles()
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
let killed = false
|
|
32
|
-
const timeout = setTimeout(() => {
|
|
33
|
-
if (!killed) {
|
|
34
|
-
setShown(true)
|
|
35
|
-
}
|
|
36
|
-
}, 300)
|
|
37
|
-
return () => {
|
|
38
|
-
clearTimeout(timeout)
|
|
39
|
-
killed = true
|
|
40
|
-
}
|
|
41
|
-
}, [])
|
|
42
|
-
|
|
43
28
|
const { status: blockStatus } = model
|
|
44
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
30
|
const { message: displayStatus } = getParent<any>(model, 2)
|
|
46
31
|
const status = displayStatus || blockStatus
|
|
47
32
|
return (
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
<LoadingEllipses message={status} />
|
|
52
|
-
</div>
|
|
53
|
-
) : null}
|
|
54
|
-
</>
|
|
33
|
+
<div className={classes.loading}>
|
|
34
|
+
<LoadingEllipses message={status} />
|
|
35
|
+
</div>
|
|
55
36
|
)
|
|
56
37
|
})
|
|
57
38
|
|
|
@@ -71,19 +52,18 @@ const ServerSideRenderedBlockContent = observer(function ({
|
|
|
71
52
|
action={model.reload}
|
|
72
53
|
/>
|
|
73
54
|
)
|
|
74
|
-
}
|
|
75
|
-
if (model.message) {
|
|
55
|
+
} else if (model.message) {
|
|
76
56
|
// the message can be a fully rendered react component, e.g. the region too large message
|
|
77
57
|
return React.isValidElement(model.message) ? (
|
|
78
58
|
model.message
|
|
79
59
|
) : (
|
|
80
60
|
<BlockMsg message={`${model.message}`} severity="info" />
|
|
81
61
|
)
|
|
82
|
-
}
|
|
83
|
-
if (!model.filled) {
|
|
62
|
+
} else if (!model.filled) {
|
|
84
63
|
return <LoadingMessage model={model} />
|
|
64
|
+
} else {
|
|
65
|
+
return model.reactElement
|
|
85
66
|
}
|
|
86
|
-
return model.reactElement
|
|
87
67
|
})
|
|
88
68
|
|
|
89
69
|
export default ServerSideRenderedBlockContent
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import { FeatureDensityStats } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
3
|
+
|
|
4
|
+
// locals
|
|
2
5
|
import BlockMsg from '../components/BlockMsg'
|
|
3
|
-
import { Stats } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
4
6
|
|
|
5
7
|
function TooLargeMessage({
|
|
6
8
|
model,
|
|
7
9
|
}: {
|
|
8
10
|
model: {
|
|
9
11
|
regionTooLargeReason: string
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
featureDensityStats?: FeatureDensityStats
|
|
13
|
+
setFeatureDensityStatsLimit: (s?: FeatureDensityStats) => void
|
|
12
14
|
reload: () => void
|
|
13
15
|
}
|
|
14
16
|
}) {
|
|
@@ -17,16 +19,16 @@ function TooLargeMessage({
|
|
|
17
19
|
<BlockMsg
|
|
18
20
|
severity="warning"
|
|
19
21
|
action={() => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} else {
|
|
23
|
-
model.updateStatsLimit(model.estimatedRegionStats)
|
|
24
|
-
model.reload()
|
|
25
|
-
}
|
|
22
|
+
model.setFeatureDensityStatsLimit(model.featureDensityStats)
|
|
23
|
+
model.reload()
|
|
26
24
|
}}
|
|
27
25
|
buttonText="Force load"
|
|
28
|
-
message={
|
|
29
|
-
|
|
26
|
+
message={[
|
|
27
|
+
regionTooLargeReason,
|
|
28
|
+
'Zoom in to see features or force load (may be slow)',
|
|
29
|
+
]
|
|
30
|
+
.filter(f => !!f)
|
|
31
|
+
.join('. ')}
|
|
30
32
|
/>
|
|
31
33
|
)
|
|
32
34
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import React from 'react'
|
|
3
|
+
import { ThemeOptions } from '@mui/material'
|
|
3
4
|
import { BaseDisplay } from '@jbrowse/core/pluggableElementTypes/models'
|
|
4
|
-
import { getConf } from '@jbrowse/core/configuration'
|
|
5
|
+
import { ConfigurationReference, getConf } from '@jbrowse/core/configuration'
|
|
5
6
|
import { MenuItem } from '@jbrowse/core/ui'
|
|
6
7
|
import {
|
|
7
8
|
isAbortException,
|
|
@@ -15,14 +16,11 @@ import {
|
|
|
15
16
|
Feature,
|
|
16
17
|
ReactRendering,
|
|
17
18
|
} from '@jbrowse/core/util'
|
|
18
|
-
import {
|
|
19
|
+
import { FeatureDensityStats } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
19
20
|
import { BaseBlock } from '@jbrowse/core/util/blockTypes'
|
|
20
21
|
import { Region } from '@jbrowse/core/util/types'
|
|
21
22
|
import CompositeMap from '@jbrowse/core/util/compositeMap'
|
|
22
|
-
import {
|
|
23
|
-
getParentRenderProps,
|
|
24
|
-
getRpcSessionId,
|
|
25
|
-
} from '@jbrowse/core/util/tracks'
|
|
23
|
+
import { getParentRenderProps } from '@jbrowse/core/util/tracks'
|
|
26
24
|
import { autorun } from 'mobx'
|
|
27
25
|
import { addDisposer, isAlive, types, Instance } from 'mobx-state-tree'
|
|
28
26
|
|
|
@@ -34,7 +32,8 @@ import { LinearGenomeViewModel, ExportSvgOptions } from '../../LinearGenomeView'
|
|
|
34
32
|
import { Tooltip } from '../components/BaseLinearDisplay'
|
|
35
33
|
import TooLargeMessage from '../components/TooLargeMessage'
|
|
36
34
|
import BlockState, { renderBlockData } from './serverSideRenderedBlock'
|
|
37
|
-
import {
|
|
35
|
+
import { getId, getDisplayStr, getFeatureDensityStatsPre } from './util'
|
|
36
|
+
import configSchema from './configSchema'
|
|
38
37
|
|
|
39
38
|
type LGV = LinearGenomeViewModel
|
|
40
39
|
|
|
@@ -46,26 +45,8 @@ export interface Layout {
|
|
|
46
45
|
name: string
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
// stabilize clipid under test for snapshot
|
|
50
|
-
function getId(id: string, index: number) {
|
|
51
|
-
const isJest = typeof jest === 'undefined'
|
|
52
|
-
return `clip-${isJest ? id : 'jest'}-${index}`
|
|
53
|
-
}
|
|
54
|
-
|
|
55
48
|
type LayoutRecord = [number, number, number, number]
|
|
56
49
|
|
|
57
|
-
function getDisplayStr(totalBytes: number) {
|
|
58
|
-
let displayBp
|
|
59
|
-
if (Math.floor(totalBytes / 1000000) > 0) {
|
|
60
|
-
displayBp = `${Number.parseFloat((totalBytes / 1000000).toPrecision(3))} Mb`
|
|
61
|
-
} else if (Math.floor(totalBytes / 1000) > 0) {
|
|
62
|
-
displayBp = `${Number.parseFloat((totalBytes / 1000).toPrecision(3))} Kb`
|
|
63
|
-
} else {
|
|
64
|
-
displayBp = `${Math.floor(totalBytes)} bytes`
|
|
65
|
-
}
|
|
66
|
-
return displayBp
|
|
67
|
-
}
|
|
68
|
-
|
|
69
50
|
const minDisplayHeight = 20
|
|
70
51
|
|
|
71
52
|
/**
|
|
@@ -101,6 +82,10 @@ function stateModelFactory() {
|
|
|
101
82
|
* #property
|
|
102
83
|
*/
|
|
103
84
|
userByteSizeLimit: types.maybe(types.number),
|
|
85
|
+
/**
|
|
86
|
+
* #property
|
|
87
|
+
*/
|
|
88
|
+
configuration: ConfigurationReference(configSchema),
|
|
104
89
|
}),
|
|
105
90
|
)
|
|
106
91
|
.volatile(() => ({
|
|
@@ -109,8 +94,10 @@ function stateModelFactory() {
|
|
|
109
94
|
message: '',
|
|
110
95
|
featureIdUnderMouse: undefined as undefined | string,
|
|
111
96
|
contextMenuFeature: undefined as undefined | Feature,
|
|
112
|
-
|
|
113
|
-
|
|
97
|
+
featureDensityStatsP: undefined as
|
|
98
|
+
| undefined
|
|
99
|
+
| Promise<FeatureDensityStats>,
|
|
100
|
+
featureDensityStats: undefined as undefined | FeatureDensityStats,
|
|
114
101
|
}))
|
|
115
102
|
.views(self => ({
|
|
116
103
|
get height() {
|
|
@@ -184,7 +171,7 @@ function stateModelFactory() {
|
|
|
184
171
|
get features() {
|
|
185
172
|
const featureMaps = []
|
|
186
173
|
for (const block of self.blockState.values()) {
|
|
187
|
-
if (block
|
|
174
|
+
if (block?.features) {
|
|
188
175
|
featureMaps.push(block.features)
|
|
189
176
|
}
|
|
190
177
|
}
|
|
@@ -202,7 +189,11 @@ function stateModelFactory() {
|
|
|
202
189
|
/**
|
|
203
190
|
* #getter
|
|
204
191
|
*/
|
|
205
|
-
getFeatureOverlapping(
|
|
192
|
+
getFeatureOverlapping(
|
|
193
|
+
blockKey: string,
|
|
194
|
+
x: number,
|
|
195
|
+
y: number,
|
|
196
|
+
): string | undefined {
|
|
206
197
|
return self.blockState.get(blockKey)?.layout?.getByCoord(x, y)
|
|
207
198
|
},
|
|
208
199
|
|
|
@@ -231,7 +222,7 @@ function stateModelFactory() {
|
|
|
231
222
|
* #getter
|
|
232
223
|
*/
|
|
233
224
|
get currentBytesRequested() {
|
|
234
|
-
return self.
|
|
225
|
+
return self.featureDensityStats?.bytes || 0
|
|
235
226
|
},
|
|
236
227
|
|
|
237
228
|
/**
|
|
@@ -239,7 +230,7 @@ function stateModelFactory() {
|
|
|
239
230
|
*/
|
|
240
231
|
get currentFeatureScreenDensity() {
|
|
241
232
|
const view = getContainingView(self) as LGV
|
|
242
|
-
return (self.
|
|
233
|
+
return (self.featureDensityStats?.featureDensity || 0) * view.bpPerPx
|
|
243
234
|
},
|
|
244
235
|
|
|
245
236
|
/**
|
|
@@ -251,8 +242,8 @@ function stateModelFactory() {
|
|
|
251
242
|
/**
|
|
252
243
|
* #getter
|
|
253
244
|
*/
|
|
254
|
-
get
|
|
255
|
-
return !!self.
|
|
245
|
+
get featureDensityStatsReady() {
|
|
246
|
+
return !!self.featureDensityStats || !!self.userBpPerPxLimit
|
|
256
247
|
},
|
|
257
248
|
|
|
258
249
|
/**
|
|
@@ -261,7 +252,7 @@ function stateModelFactory() {
|
|
|
261
252
|
get maxAllowableBytes() {
|
|
262
253
|
return (
|
|
263
254
|
self.userByteSizeLimit ||
|
|
264
|
-
self.
|
|
255
|
+
self.featureDensityStats?.fetchSizeLimit ||
|
|
265
256
|
(getConf(self, 'fetchSizeLimit') as number)
|
|
266
257
|
)
|
|
267
258
|
},
|
|
@@ -273,95 +264,68 @@ function stateModelFactory() {
|
|
|
273
264
|
setMessage(message: string) {
|
|
274
265
|
self.message = message
|
|
275
266
|
},
|
|
276
|
-
|
|
267
|
+
}))
|
|
268
|
+
.actions(self => ({
|
|
277
269
|
afterAttach() {
|
|
278
270
|
// watch the parent's blocks to update our block state when they change,
|
|
279
271
|
// then we recreate the blocks on our own model (creating and deleting to
|
|
280
272
|
// match the parent blocks)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
self
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
273
|
+
addDisposer(
|
|
274
|
+
self,
|
|
275
|
+
autorun(() => {
|
|
276
|
+
const blocksPresent: { [key: string]: boolean } = {}
|
|
277
|
+
const view = getContainingView(self) as LGV
|
|
278
|
+
if (view.initialized) {
|
|
279
|
+
self.blockDefinitions.contentBlocks.forEach(block => {
|
|
280
|
+
blocksPresent[block.key] = true
|
|
281
|
+
if (!self.blockState.has(block.key)) {
|
|
282
|
+
this.addBlock(block.key, block)
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
self.blockState.forEach((_, key) => {
|
|
286
|
+
if (!blocksPresent[key]) {
|
|
287
|
+
this.deleteBlock(key)
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
}),
|
|
292
|
+
)
|
|
300
293
|
},
|
|
301
294
|
|
|
302
295
|
/**
|
|
303
296
|
* #action
|
|
304
297
|
*/
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (self.estimatedRegionStatsP) {
|
|
314
|
-
return self.estimatedRegionStatsP
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const { rpcManager } = getSession(self)
|
|
318
|
-
const { adapterConfig } = self
|
|
319
|
-
if (!adapterConfig) {
|
|
320
|
-
// A track extending the base track might not have an adapter config
|
|
321
|
-
// e.g. Apollo tracks don't use adapters
|
|
322
|
-
return Promise.resolve({})
|
|
323
|
-
}
|
|
324
|
-
const sessionId = getRpcSessionId(self)
|
|
325
|
-
|
|
326
|
-
const params = {
|
|
327
|
-
sessionId,
|
|
328
|
-
regions,
|
|
329
|
-
adapterConfig,
|
|
330
|
-
statusCallback: (message: string) => {
|
|
331
|
-
if (isAlive(self)) {
|
|
332
|
-
this.setMessage(message)
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
...opts,
|
|
298
|
+
async getFeatureDensityStats() {
|
|
299
|
+
if (!self.featureDensityStatsP) {
|
|
300
|
+
self.featureDensityStatsP = getFeatureDensityStatsPre(self).catch(
|
|
301
|
+
e => {
|
|
302
|
+
this.setFeatureDensityStatsP(undefined)
|
|
303
|
+
throw e
|
|
304
|
+
},
|
|
305
|
+
)
|
|
336
306
|
}
|
|
337
|
-
|
|
338
|
-
self.estimatedRegionStatsP = rpcManager
|
|
339
|
-
.call(sessionId, 'CoreEstimateRegionStats', params)
|
|
340
|
-
.catch(e => {
|
|
341
|
-
this.setRegionStatsP(undefined)
|
|
342
|
-
throw e
|
|
343
|
-
}) as Promise<Stats>
|
|
344
|
-
|
|
345
|
-
return self.estimatedRegionStatsP
|
|
307
|
+
return self.featureDensityStatsP
|
|
346
308
|
},
|
|
309
|
+
|
|
347
310
|
/**
|
|
348
311
|
* #action
|
|
349
312
|
*/
|
|
350
|
-
|
|
351
|
-
self.
|
|
313
|
+
setFeatureDensityStatsP(arg: any) {
|
|
314
|
+
self.featureDensityStatsP = arg
|
|
352
315
|
},
|
|
316
|
+
|
|
353
317
|
/**
|
|
354
318
|
* #action
|
|
355
319
|
*/
|
|
356
|
-
|
|
357
|
-
self.
|
|
320
|
+
setFeatureDensityStats(featureDensityStats?: FeatureDensityStats) {
|
|
321
|
+
self.featureDensityStats = featureDensityStats
|
|
358
322
|
},
|
|
359
323
|
/**
|
|
360
324
|
* #action
|
|
361
325
|
*/
|
|
362
|
-
|
|
363
|
-
self.
|
|
364
|
-
self.
|
|
326
|
+
clearFeatureDensityStats() {
|
|
327
|
+
self.featureDensityStatsP = undefined
|
|
328
|
+
self.featureDensityStats = undefined
|
|
365
329
|
},
|
|
366
330
|
/**
|
|
367
331
|
* #action
|
|
@@ -390,9 +354,9 @@ function stateModelFactory() {
|
|
|
390
354
|
/**
|
|
391
355
|
* #action
|
|
392
356
|
*/
|
|
393
|
-
|
|
357
|
+
setFeatureDensityStatsLimit(stats?: FeatureDensityStats) {
|
|
394
358
|
const view = getContainingView(self) as LGV
|
|
395
|
-
if (stats
|
|
359
|
+
if (stats?.bytes) {
|
|
396
360
|
self.userByteSizeLimit = stats.bytes
|
|
397
361
|
} else {
|
|
398
362
|
self.userBpPerPxLimit = view.bpPerPx
|
|
@@ -449,13 +413,12 @@ function stateModelFactory() {
|
|
|
449
413
|
* #action
|
|
450
414
|
*/
|
|
451
415
|
clearFeatureSelection() {
|
|
452
|
-
|
|
453
|
-
session.clearSelection()
|
|
416
|
+
getSession(self).clearSelection()
|
|
454
417
|
},
|
|
455
418
|
/**
|
|
456
419
|
* #action
|
|
457
420
|
*/
|
|
458
|
-
setFeatureIdUnderMouse(feature
|
|
421
|
+
setFeatureIdUnderMouse(feature?: string) {
|
|
459
422
|
self.featureIdUnderMouse = feature
|
|
460
423
|
},
|
|
461
424
|
/**
|
|
@@ -477,20 +440,22 @@ function stateModelFactory() {
|
|
|
477
440
|
* region is too large if:
|
|
478
441
|
* - stats are ready
|
|
479
442
|
* - region is greater than 20kb (don't warn when zoomed in less than that)
|
|
480
|
-
* - and bytes is greater than max allowed bytes or density greater than max
|
|
443
|
+
* - and bytes is greater than max allowed bytes or density greater than max
|
|
444
|
+
* density
|
|
481
445
|
*/
|
|
482
446
|
get regionTooLarge() {
|
|
483
447
|
const view = getContainingView(self) as LGV
|
|
484
|
-
if (
|
|
448
|
+
if (
|
|
449
|
+
!self.featureDensityStatsReady ||
|
|
450
|
+
view.dynamicBlocks.totalBp < 20_000
|
|
451
|
+
) {
|
|
485
452
|
return false
|
|
486
453
|
}
|
|
487
|
-
const bpLimitOrDensity = self.userBpPerPxLimit
|
|
488
|
-
? view.bpPerPx > self.userBpPerPxLimit
|
|
489
|
-
: self.currentFeatureScreenDensity > self.maxFeatureScreenDensity
|
|
490
|
-
|
|
491
454
|
return (
|
|
492
455
|
self.currentBytesRequested > self.maxAllowableBytes ||
|
|
493
|
-
|
|
456
|
+
(self.userBpPerPxLimit
|
|
457
|
+
? view.bpPerPx > self.userBpPerPxLimit
|
|
458
|
+
: self.currentFeatureScreenDensity > self.maxFeatureScreenDensity)
|
|
494
459
|
)
|
|
495
460
|
},
|
|
496
461
|
|
|
@@ -517,7 +482,6 @@ function stateModelFactory() {
|
|
|
517
482
|
*/
|
|
518
483
|
async reload() {
|
|
519
484
|
self.setError()
|
|
520
|
-
const aborter = new AbortController()
|
|
521
485
|
const view = getContainingView(self) as LGV
|
|
522
486
|
|
|
523
487
|
// extra check for contentBlocks.length
|
|
@@ -527,84 +491,70 @@ function stateModelFactory() {
|
|
|
527
491
|
}
|
|
528
492
|
|
|
529
493
|
try {
|
|
530
|
-
|
|
531
|
-
view.staticBlocks.contentBlocks,
|
|
532
|
-
{ signal: aborter.signal },
|
|
533
|
-
)
|
|
534
|
-
const estimatedRegionStats = await self.estimatedRegionStatsP
|
|
494
|
+
const featureDensityStats = await self.getFeatureDensityStats()
|
|
535
495
|
|
|
536
496
|
if (isAlive(self)) {
|
|
537
|
-
self.
|
|
497
|
+
self.setFeatureDensityStats(featureDensityStats)
|
|
538
498
|
superReload()
|
|
539
|
-
} else {
|
|
540
|
-
return
|
|
541
499
|
}
|
|
542
500
|
} catch (e) {
|
|
543
501
|
console.error(e)
|
|
544
502
|
self.setError(e)
|
|
545
503
|
}
|
|
546
504
|
},
|
|
547
|
-
afterAttach() {
|
|
548
|
-
// this autorun performs stats estimation
|
|
549
|
-
//
|
|
550
|
-
// the chain of events calls estimateRegionsStats against the data
|
|
551
|
-
// adapter which by default uses featureDensity, but can also respond
|
|
552
|
-
// with a byte size estimate and fetch size limit (data adapter can
|
|
553
|
-
// define what is too much data)
|
|
554
|
-
addDisposer(
|
|
555
|
-
self,
|
|
556
|
-
autorun(
|
|
557
|
-
async () => {
|
|
558
|
-
try {
|
|
559
|
-
const aborter = new AbortController()
|
|
560
|
-
const view = getContainingView(self) as LGV
|
|
561
|
-
|
|
562
|
-
// extra check for contentBlocks.length
|
|
563
|
-
// https://github.com/GMOD/jbrowse-components/issues/2694
|
|
564
|
-
if (
|
|
565
|
-
!view.initialized ||
|
|
566
|
-
!view.staticBlocks.contentBlocks.length
|
|
567
|
-
) {
|
|
568
|
-
return
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// don't re-estimate featureDensity even if zoom level changes,
|
|
572
|
-
// jbrowse1-style assume it's sort of representative
|
|
573
|
-
if (self.estimatedRegionStats?.featureDensity !== undefined) {
|
|
574
|
-
self.setCurrBpPerPx(view.bpPerPx)
|
|
575
|
-
return
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// we estimate stats once at a given zoom level
|
|
579
|
-
if (view.bpPerPx === self.currBpPerPx) {
|
|
580
|
-
return
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
self.clearRegionStats()
|
|
584
|
-
self.setCurrBpPerPx(view.bpPerPx)
|
|
585
|
-
const statsP = self.estimateRegionsStats(
|
|
586
|
-
view.staticBlocks.contentBlocks,
|
|
587
|
-
{ signal: aborter.signal },
|
|
588
|
-
)
|
|
589
|
-
self.setRegionStatsP(statsP)
|
|
590
|
-
const estimatedRegionStats = await statsP
|
|
591
|
-
|
|
592
|
-
if (isAlive(self)) {
|
|
593
|
-
self.setRegionStats(estimatedRegionStats)
|
|
594
|
-
}
|
|
595
|
-
} catch (e) {
|
|
596
|
-
if (!isAbortException(e) && isAlive(self)) {
|
|
597
|
-
console.error(e)
|
|
598
|
-
self.setError(e)
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
},
|
|
602
|
-
{ delay: 500 },
|
|
603
|
-
),
|
|
604
|
-
)
|
|
605
|
-
},
|
|
606
505
|
}
|
|
607
506
|
})
|
|
507
|
+
.actions(self => ({
|
|
508
|
+
afterAttach() {
|
|
509
|
+
// this autorun performs stats estimation
|
|
510
|
+
//
|
|
511
|
+
// the chain of events calls getFeatureDensityStats against the data
|
|
512
|
+
// adapter which by default uses featureDensity, but can also respond
|
|
513
|
+
// with a byte size estimate and fetch size limit (data adapter can
|
|
514
|
+
// define what is too much data)
|
|
515
|
+
addDisposer(
|
|
516
|
+
self,
|
|
517
|
+
autorun(async () => {
|
|
518
|
+
try {
|
|
519
|
+
const view = getContainingView(self) as LGV
|
|
520
|
+
|
|
521
|
+
// extra check for contentBlocks.length
|
|
522
|
+
// https://github.com/GMOD/jbrowse-components/issues/2694
|
|
523
|
+
if (
|
|
524
|
+
!view.initialized ||
|
|
525
|
+
!view.staticBlocks.contentBlocks.length
|
|
526
|
+
) {
|
|
527
|
+
return
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// don't re-estimate featureDensity even if zoom level changes,
|
|
531
|
+
// jbrowse1-style assume it's sort of representative
|
|
532
|
+
if (self.featureDensityStats?.featureDensity !== undefined) {
|
|
533
|
+
self.setCurrBpPerPx(view.bpPerPx)
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// we estimate stats once at a given zoom level
|
|
538
|
+
if (view.bpPerPx === self.currBpPerPx) {
|
|
539
|
+
return
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
self.clearFeatureDensityStats()
|
|
543
|
+
self.setCurrBpPerPx(view.bpPerPx)
|
|
544
|
+
const featureDensityStats = await self.getFeatureDensityStats()
|
|
545
|
+
if (isAlive(self)) {
|
|
546
|
+
self.setFeatureDensityStats(featureDensityStats)
|
|
547
|
+
}
|
|
548
|
+
} catch (e) {
|
|
549
|
+
if (!isAbortException(e) && isAlive(self)) {
|
|
550
|
+
console.error(e)
|
|
551
|
+
self.setError(e)
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}),
|
|
555
|
+
)
|
|
556
|
+
},
|
|
557
|
+
}))
|
|
608
558
|
.views(self => ({
|
|
609
559
|
/**
|
|
610
560
|
* #method
|
|
@@ -622,8 +572,7 @@ function stateModelFactory() {
|
|
|
622
572
|
* react node allows user to force load at current setting
|
|
623
573
|
*/
|
|
624
574
|
regionCannotBeRendered(_region: Region) {
|
|
625
|
-
|
|
626
|
-
return regionTooLarge ? <TooLargeMessage model={self} /> : null
|
|
575
|
+
return self.regionTooLarge ? <TooLargeMessage model={self} /> : null
|
|
627
576
|
},
|
|
628
577
|
|
|
629
578
|
/**
|
|
@@ -636,20 +585,22 @@ function stateModelFactory() {
|
|
|
636
585
|
/**
|
|
637
586
|
* #method
|
|
638
587
|
*/
|
|
639
|
-
contextMenuItems() {
|
|
640
|
-
return
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
588
|
+
contextMenuItems(): MenuItem[] {
|
|
589
|
+
return [
|
|
590
|
+
...(self.contextMenuFeature
|
|
591
|
+
? [
|
|
592
|
+
{
|
|
593
|
+
label: 'Open feature details',
|
|
594
|
+
icon: MenuOpenIcon,
|
|
595
|
+
onClick: () => {
|
|
596
|
+
if (self.contextMenuFeature) {
|
|
597
|
+
self.selectFeature(self.contextMenuFeature)
|
|
598
|
+
}
|
|
599
|
+
},
|
|
649
600
|
},
|
|
650
|
-
|
|
651
|
-
]
|
|
652
|
-
|
|
601
|
+
]
|
|
602
|
+
: []),
|
|
603
|
+
]
|
|
653
604
|
},
|
|
654
605
|
/**
|
|
655
606
|
* #method
|
|
@@ -659,7 +610,7 @@ function stateModelFactory() {
|
|
|
659
610
|
return {
|
|
660
611
|
...getParentRenderProps(self),
|
|
661
612
|
notReady:
|
|
662
|
-
self.currBpPerPx !== view.bpPerPx || !self.
|
|
613
|
+
self.currBpPerPx !== view.bpPerPx || !self.featureDensityStatsReady,
|
|
663
614
|
rpcDriverName: self.rpcDriverName,
|
|
664
615
|
displayModel: self,
|
|
665
616
|
onFeatureClick(_: unknown, featureId?: string) {
|
|
@@ -37,6 +37,16 @@ const baseLinearDisplayConfigSchema = ConfigurationSchema(
|
|
|
37
37
|
defaultValue: 100,
|
|
38
38
|
description: 'default height for the track',
|
|
39
39
|
},
|
|
40
|
+
/**
|
|
41
|
+
* #slot
|
|
42
|
+
*/
|
|
43
|
+
mouseover: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'text to display when the cursor hovers over a feature',
|
|
46
|
+
defaultValue: `jexl:get(feature,'name')`,
|
|
47
|
+
|
|
48
|
+
contextVariable: ['feature'],
|
|
49
|
+
},
|
|
40
50
|
},
|
|
41
51
|
{
|
|
42
52
|
/**
|