@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.
Files changed (201) hide show
  1. package/dist/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -4
  2. package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +8 -43
  3. package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
  4. package/dist/BaseLinearDisplay/components/TooLargeMessage.d.ts +3 -4
  5. package/dist/BaseLinearDisplay/components/TooLargeMessage.js +9 -9
  6. package/dist/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -1
  7. package/dist/BaseLinearDisplay/components/Tooltip.d.ts +0 -1
  8. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +81 -35
  9. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +105 -143
  10. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
  11. package/dist/BaseLinearDisplay/models/configSchema.d.ts +35 -1
  12. package/dist/BaseLinearDisplay/models/configSchema.js +9 -0
  13. package/dist/BaseLinearDisplay/models/configSchema.js.map +1 -1
  14. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js +10 -6
  15. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
  16. package/dist/BaseLinearDisplay/models/util.d.ts +8 -0
  17. package/dist/BaseLinearDisplay/models/util.js +33 -1
  18. package/dist/BaseLinearDisplay/models/util.js.map +1 -1
  19. package/dist/BasicTrack/configSchema.d.ts +73 -1
  20. package/dist/FeatureTrack/configSchema.d.ts +75 -1
  21. package/dist/LinearBareDisplay/configSchema.d.ts +28 -1
  22. package/dist/LinearBareDisplay/index.js +1 -0
  23. package/dist/LinearBareDisplay/index.js.map +1 -1
  24. package/dist/LinearBareDisplay/model.d.ts +66 -23
  25. package/dist/LinearBareDisplay/model.js +2 -2
  26. package/dist/LinearBareDisplay/model.js.map +1 -1
  27. package/dist/LinearBasicDisplay/components/SetMaxHeight.d.ts +1 -2
  28. package/dist/LinearBasicDisplay/components/SetMaxHeight.js +2 -5
  29. package/dist/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
  30. package/dist/LinearBasicDisplay/configSchema.d.ts +28 -1
  31. package/dist/LinearBasicDisplay/configSchema.js +0 -9
  32. package/dist/LinearBasicDisplay/configSchema.js.map +1 -1
  33. package/dist/LinearBasicDisplay/index.js +1 -1
  34. package/dist/LinearBasicDisplay/model.d.ts +76 -36
  35. package/dist/LinearBasicDisplay/model.js.map +1 -1
  36. package/dist/LinearGenomeView/components/CenterLine.d.ts +0 -1
  37. package/dist/LinearGenomeView/components/Cytobands.d.ts +22 -23
  38. package/dist/LinearGenomeView/components/ExportSvgDialog.d.ts +0 -1
  39. package/dist/LinearGenomeView/components/GetSequenceDialog.d.ts +0 -1
  40. package/dist/LinearGenomeView/components/GetSequenceDialog.js +14 -16
  41. package/dist/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
  42. package/dist/LinearGenomeView/components/Gridlines.d.ts +0 -1
  43. package/dist/LinearGenomeView/components/Header.d.ts +0 -1
  44. package/dist/LinearGenomeView/components/HelpDialog.d.ts +0 -1
  45. package/dist/LinearGenomeView/components/ImportForm.d.ts +0 -1
  46. package/dist/LinearGenomeView/components/ImportForm.js +4 -7
  47. package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
  48. package/dist/LinearGenomeView/components/LinearGenomeView.d.ts +0 -1
  49. package/dist/LinearGenomeView/components/LinearGenomeView.js +0 -4
  50. package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
  51. package/dist/LinearGenomeView/components/MiniControls.d.ts +0 -1
  52. package/dist/LinearGenomeView/components/OverviewScalebar.js +2 -1
  53. package/dist/LinearGenomeView/components/OverviewScalebar.js.map +1 -1
  54. package/dist/LinearGenomeView/components/RefNameAutocomplete.js +53 -52
  55. package/dist/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
  56. package/dist/LinearGenomeView/components/RubberbandSpan.d.ts +0 -1
  57. package/dist/LinearGenomeView/components/SearchBox.d.ts +0 -1
  58. package/dist/LinearGenomeView/components/SearchResultsDialog.d.ts +5 -3
  59. package/dist/LinearGenomeView/components/SearchResultsDialog.js +6 -82
  60. package/dist/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
  61. package/dist/LinearGenomeView/components/SearchResultsTable.d.ts +8 -0
  62. package/dist/LinearGenomeView/components/SearchResultsTable.js +83 -0
  63. package/dist/LinearGenomeView/components/SearchResultsTable.js.map +1 -0
  64. package/dist/LinearGenomeView/components/SequenceSearchDialog.d.ts +0 -1
  65. package/dist/LinearGenomeView/components/TrackContainer.d.ts +0 -1
  66. package/dist/LinearGenomeView/components/TrackContainer.js +8 -2
  67. package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -1
  68. package/dist/LinearGenomeView/components/TracksContainer.js +5 -7
  69. package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -1
  70. package/dist/LinearGenomeView/components/VerticalGuide.d.ts +0 -1
  71. package/dist/LinearGenomeView/components/ZoomControls.d.ts +0 -1
  72. package/dist/LinearGenomeView/components/util.js +1 -1
  73. package/dist/LinearGenomeView/components/util.js.map +1 -1
  74. package/dist/LinearGenomeView/model.d.ts +49 -36
  75. package/dist/LinearGenomeView/model.js +121 -198
  76. package/dist/LinearGenomeView/model.js.map +1 -1
  77. package/dist/LinearGenomeView/svgcomponents/SVGBackground.d.ts +0 -1
  78. package/dist/LinearGenomeView/svgcomponents/SVGHeader.d.ts +0 -1
  79. package/dist/LinearGenomeView/svgcomponents/SVGRegionSeparators.d.ts +0 -1
  80. package/dist/LinearGenomeView/svgcomponents/SVGRuler.d.ts +0 -1
  81. package/dist/LinearGenomeView/svgcomponents/SVGScalebar.d.ts +0 -1
  82. package/dist/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +0 -1
  83. package/dist/LinearGenomeView/svgcomponents/SVGTracks.d.ts +0 -1
  84. package/dist/LinearGenomeView/util.d.ts +29 -0
  85. package/dist/LinearGenomeView/util.js +79 -1
  86. package/dist/LinearGenomeView/util.js.map +1 -1
  87. package/dist/index.d.ts +201 -106
  88. package/esm/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -4
  89. package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +8 -20
  90. package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
  91. package/esm/BaseLinearDisplay/components/TooLargeMessage.d.ts +3 -4
  92. package/esm/BaseLinearDisplay/components/TooLargeMessage.js +9 -9
  93. package/esm/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -1
  94. package/esm/BaseLinearDisplay/components/Tooltip.d.ts +0 -1
  95. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +81 -35
  96. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +105 -143
  97. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
  98. package/esm/BaseLinearDisplay/models/configSchema.d.ts +35 -1
  99. package/esm/BaseLinearDisplay/models/configSchema.js +9 -0
  100. package/esm/BaseLinearDisplay/models/configSchema.js.map +1 -1
  101. package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js +10 -6
  102. package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
  103. package/esm/BaseLinearDisplay/models/util.d.ts +8 -0
  104. package/esm/BaseLinearDisplay/models/util.js +30 -0
  105. package/esm/BaseLinearDisplay/models/util.js.map +1 -1
  106. package/esm/BasicTrack/configSchema.d.ts +73 -1
  107. package/esm/FeatureTrack/configSchema.d.ts +75 -1
  108. package/esm/LinearBareDisplay/configSchema.d.ts +28 -1
  109. package/esm/LinearBareDisplay/index.js +1 -0
  110. package/esm/LinearBareDisplay/index.js.map +1 -1
  111. package/esm/LinearBareDisplay/model.d.ts +66 -23
  112. package/esm/LinearBareDisplay/model.js +1 -1
  113. package/esm/LinearBareDisplay/model.js.map +1 -1
  114. package/esm/LinearBasicDisplay/components/SetMaxHeight.d.ts +1 -2
  115. package/esm/LinearBasicDisplay/components/SetMaxHeight.js +2 -5
  116. package/esm/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
  117. package/esm/LinearBasicDisplay/configSchema.d.ts +28 -1
  118. package/esm/LinearBasicDisplay/configSchema.js +0 -9
  119. package/esm/LinearBasicDisplay/configSchema.js.map +1 -1
  120. package/esm/LinearBasicDisplay/index.js +1 -1
  121. package/esm/LinearBasicDisplay/model.d.ts +76 -36
  122. package/esm/LinearBasicDisplay/model.js.map +1 -1
  123. package/esm/LinearGenomeView/components/CenterLine.d.ts +0 -1
  124. package/esm/LinearGenomeView/components/Cytobands.d.ts +22 -23
  125. package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +0 -1
  126. package/esm/LinearGenomeView/components/GetSequenceDialog.d.ts +0 -1
  127. package/esm/LinearGenomeView/components/GetSequenceDialog.js +15 -17
  128. package/esm/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
  129. package/esm/LinearGenomeView/components/Gridlines.d.ts +0 -1
  130. package/esm/LinearGenomeView/components/Header.d.ts +0 -1
  131. package/esm/LinearGenomeView/components/HelpDialog.d.ts +0 -1
  132. package/esm/LinearGenomeView/components/ImportForm.d.ts +0 -1
  133. package/esm/LinearGenomeView/components/ImportForm.js +5 -8
  134. package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
  135. package/esm/LinearGenomeView/components/LinearGenomeView.d.ts +0 -1
  136. package/esm/LinearGenomeView/components/LinearGenomeView.js +0 -4
  137. package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
  138. package/esm/LinearGenomeView/components/MiniControls.d.ts +0 -1
  139. package/esm/LinearGenomeView/components/OverviewScalebar.js +2 -1
  140. package/esm/LinearGenomeView/components/OverviewScalebar.js.map +1 -1
  141. package/esm/LinearGenomeView/components/RefNameAutocomplete.js +53 -52
  142. package/esm/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
  143. package/esm/LinearGenomeView/components/RubberbandSpan.d.ts +0 -1
  144. package/esm/LinearGenomeView/components/SearchBox.d.ts +0 -1
  145. package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +5 -3
  146. package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -83
  147. package/esm/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
  148. package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +8 -0
  149. package/esm/LinearGenomeView/components/SearchResultsTable.js +77 -0
  150. package/esm/LinearGenomeView/components/SearchResultsTable.js.map +1 -0
  151. package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +0 -1
  152. package/esm/LinearGenomeView/components/TrackContainer.d.ts +0 -1
  153. package/esm/LinearGenomeView/components/TrackContainer.js +8 -2
  154. package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -1
  155. package/esm/LinearGenomeView/components/TracksContainer.js +5 -7
  156. package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -1
  157. package/esm/LinearGenomeView/components/VerticalGuide.d.ts +0 -1
  158. package/esm/LinearGenomeView/components/ZoomControls.d.ts +0 -1
  159. package/esm/LinearGenomeView/components/util.js +1 -1
  160. package/esm/LinearGenomeView/components/util.js.map +1 -1
  161. package/esm/LinearGenomeView/model.d.ts +49 -36
  162. package/esm/LinearGenomeView/model.js +122 -199
  163. package/esm/LinearGenomeView/model.js.map +1 -1
  164. package/esm/LinearGenomeView/svgcomponents/SVGBackground.d.ts +0 -1
  165. package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +0 -1
  166. package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.d.ts +0 -1
  167. package/esm/LinearGenomeView/svgcomponents/SVGRuler.d.ts +0 -1
  168. package/esm/LinearGenomeView/svgcomponents/SVGScalebar.d.ts +0 -1
  169. package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +0 -1
  170. package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +0 -1
  171. package/esm/LinearGenomeView/util.d.ts +29 -0
  172. package/esm/LinearGenomeView/util.js +76 -0
  173. package/esm/LinearGenomeView/util.js.map +1 -1
  174. package/esm/index.d.ts +201 -106
  175. package/package.json +3 -3
  176. package/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx +8 -28
  177. package/src/BaseLinearDisplay/components/TooLargeMessage.tsx +13 -11
  178. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +148 -197
  179. package/src/BaseLinearDisplay/models/configSchema.ts +10 -0
  180. package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +19 -13
  181. package/src/BaseLinearDisplay/models/util.ts +43 -0
  182. package/src/LinearBareDisplay/index.ts +1 -0
  183. package/src/LinearBareDisplay/model.ts +1 -1
  184. package/src/LinearBasicDisplay/components/SetMaxHeight.tsx +3 -7
  185. package/src/LinearBasicDisplay/configSchema.ts +0 -10
  186. package/src/LinearBasicDisplay/index.ts +1 -1
  187. package/src/LinearBasicDisplay/model.ts +1 -1
  188. package/src/LinearGenomeView/components/GetSequenceDialog.tsx +15 -25
  189. package/src/LinearGenomeView/components/ImportForm.tsx +4 -14
  190. package/src/LinearGenomeView/components/LinearGenomeView.tsx +0 -14
  191. package/src/LinearGenomeView/components/OverviewScalebar.tsx +2 -1
  192. package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +122 -82
  193. package/src/LinearGenomeView/components/SearchResultsDialog.tsx +17 -112
  194. package/src/LinearGenomeView/components/SearchResultsTable.tsx +121 -0
  195. package/src/LinearGenomeView/components/TrackContainer.tsx +12 -3
  196. package/src/LinearGenomeView/components/TracksContainer.tsx +9 -6
  197. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +11 -11
  198. package/src/LinearGenomeView/components/util.ts +2 -1
  199. package/src/LinearGenomeView/index.test.ts +10 -12
  200. package/src/LinearGenomeView/model.ts +163 -236
  201. 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.4.1",
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": "^3.0.0",
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": "747c50c4edc0184827efa4f8dfc576ca9a72caeb"
69
+ "gitHead": "d1ca073996d008f0fe9a52f7c1a47ae649dcfdaf"
70
70
  }
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from '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
- {shown ? (
50
- <div className={classes.loading}>
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
- estimatedRegionStats?: Stats
11
- updateStatsLimit: (s: Stats) => void
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
- if (!model.estimatedRegionStats) {
21
- console.error('No global stats?')
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={`${regionTooLargeReason ? regionTooLargeReason + '. ' : ''}
29
- Zoom in to see features or force load (may be slow).`}
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 { Stats } from '@jbrowse/core/data_adapters/BaseAdapter'
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 { ThemeOptions } from '@mui/material'
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
- estimatedRegionStatsP: undefined as undefined | Promise<Stats>,
113
- estimatedRegionStats: undefined as undefined | Stats,
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 && block.features) {
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(blockKey: string, x: number, y: number) {
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.estimatedRegionStats?.bytes || 0
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.estimatedRegionStats?.featureDensity || 0) * view.bpPerPx
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 estimatedStatsReady() {
255
- return !!self.estimatedRegionStats
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.estimatedRegionStats?.fetchSizeLimit ||
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
- const blockWatchDisposer = autorun(() => {
282
- const blocksPresent: { [key: string]: boolean } = {}
283
- const view = getContainingView(self) as LGV
284
- if (view.initialized) {
285
- self.blockDefinitions.contentBlocks.forEach(block => {
286
- blocksPresent[block.key] = true
287
- if (!self.blockState.has(block.key)) {
288
- this.addBlock(block.key, block)
289
- }
290
- })
291
- self.blockState.forEach((_, key) => {
292
- if (!blocksPresent[key]) {
293
- this.deleteBlock(key)
294
- }
295
- })
296
- }
297
- })
298
-
299
- addDisposer(self, blockWatchDisposer)
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
- estimateRegionsStats(
306
- regions: Region[],
307
- opts: {
308
- headers?: Record<string, string>
309
- signal?: AbortSignal
310
- filters?: string[]
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
- setRegionStatsP(p?: Promise<Stats>) {
351
- self.estimatedRegionStatsP = p
313
+ setFeatureDensityStatsP(arg: any) {
314
+ self.featureDensityStatsP = arg
352
315
  },
316
+
353
317
  /**
354
318
  * #action
355
319
  */
356
- setRegionStats(estimatedRegionStats?: Stats) {
357
- self.estimatedRegionStats = estimatedRegionStats
320
+ setFeatureDensityStats(featureDensityStats?: FeatureDensityStats) {
321
+ self.featureDensityStats = featureDensityStats
358
322
  },
359
323
  /**
360
324
  * #action
361
325
  */
362
- clearRegionStats() {
363
- self.estimatedRegionStatsP = undefined
364
- self.estimatedRegionStats = undefined
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
- updateStatsLimit(stats: Stats) {
357
+ setFeatureDensityStatsLimit(stats?: FeatureDensityStats) {
394
358
  const view = getContainingView(self) as LGV
395
- if (stats.bytes) {
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
- const session = getSession(self)
453
- session.clearSelection()
416
+ getSession(self).clearSelection()
454
417
  },
455
418
  /**
456
419
  * #action
457
420
  */
458
- setFeatureIdUnderMouse(feature: string | undefined) {
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 density
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 (!self.estimatedStatsReady || view.dynamicBlocks.totalBp < 20_000) {
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
- bpLimitOrDensity
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
- self.estimatedRegionStatsP = self.estimateRegionsStats(
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.setRegionStats(estimatedRegionStats)
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
- const { regionTooLarge } = self
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 self.contextMenuFeature
641
- ? [
642
- {
643
- label: 'Open feature details',
644
- icon: MenuOpenIcon,
645
- onClick: () => {
646
- if (self.contextMenuFeature) {
647
- self.selectFeature(self.contextMenuFeature)
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.estimatedRegionStats,
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
  /**