@jbrowse/plugin-linear-genome-view 2.2.0 → 2.2.2

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 (225) hide show
  1. package/dist/BaseLinearDisplay/components/Tooltip.d.ts +1 -1
  2. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +3 -3
  3. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
  4. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js +1 -1
  5. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
  6. package/dist/BasicTrack/index.d.ts +1 -1
  7. package/dist/BasicTrack/index.js +4 -4
  8. package/dist/BasicTrack/index.js.map +1 -1
  9. package/dist/LaunchLinearGenomeView/index.d.ts +3 -0
  10. package/dist/LaunchLinearGenomeView/index.js +44 -0
  11. package/dist/LaunchLinearGenomeView/index.js.map +1 -0
  12. package/dist/LinearBareDisplay/index.d.ts +6 -2
  13. package/dist/LinearBareDisplay/index.js +17 -2
  14. package/dist/LinearBareDisplay/index.js.map +1 -1
  15. package/dist/LinearBasicDisplay/components/SetMaxHeight.js +2 -15
  16. package/dist/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
  17. package/dist/LinearBasicDisplay/index.d.ts +6 -2
  18. package/dist/LinearBasicDisplay/index.js +20 -4
  19. package/dist/LinearBasicDisplay/index.js.map +1 -1
  20. package/dist/LinearBasicDisplay/model.d.ts +21 -14
  21. package/dist/LinearBasicDisplay/model.js +2 -1
  22. package/dist/LinearBasicDisplay/model.js.map +1 -1
  23. package/dist/LinearGenomeView/components/CenterLine.d.ts +1 -1
  24. package/dist/LinearGenomeView/components/ExportSvgDialog.js +1 -19
  25. package/dist/LinearGenomeView/components/ExportSvgDialog.js.map +1 -1
  26. package/dist/LinearGenomeView/components/GetSequenceDialog.d.ts +1 -1
  27. package/dist/LinearGenomeView/components/GetSequenceDialog.js +7 -18
  28. package/dist/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
  29. package/dist/LinearGenomeView/components/Gridlines.d.ts +1 -1
  30. package/dist/LinearGenomeView/components/Header.d.ts +1 -1
  31. package/dist/LinearGenomeView/components/Header.js +2 -2
  32. package/dist/LinearGenomeView/components/HelpDialog.js +2 -17
  33. package/dist/LinearGenomeView/components/HelpDialog.js.map +1 -1
  34. package/dist/LinearGenomeView/components/ImportForm.d.ts +1 -1
  35. package/dist/LinearGenomeView/components/ImportForm.js +18 -16
  36. package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
  37. package/dist/LinearGenomeView/components/LinearGenomeView.d.ts +1 -1
  38. package/dist/LinearGenomeView/components/LinearGenomeView.js +1 -3
  39. package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
  40. package/dist/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +1 -1
  41. package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js +5 -5
  42. package/dist/LinearGenomeView/components/{OverviewRubberBand.d.ts → OverviewRubberband.d.ts} +3 -3
  43. package/dist/LinearGenomeView/components/{OverviewRubberBand.js → OverviewRubberband.js} +27 -79
  44. package/dist/LinearGenomeView/components/OverviewRubberband.js.map +1 -0
  45. package/{esm/LinearGenomeView/components/OverviewScaleBar.d.ts → dist/LinearGenomeView/components/OverviewScalebar.d.ts} +3 -3
  46. package/dist/LinearGenomeView/components/{OverviewScaleBar.js → OverviewScalebar.js} +25 -24
  47. package/dist/LinearGenomeView/components/OverviewScalebar.js.map +1 -0
  48. package/dist/LinearGenomeView/components/RefNameAutocomplete.js +1 -1
  49. package/dist/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
  50. package/dist/LinearGenomeView/components/{RubberBand.d.ts → Rubberband.d.ts} +3 -3
  51. package/dist/LinearGenomeView/components/Rubberband.js +57 -0
  52. package/dist/LinearGenomeView/components/Rubberband.js.map +1 -0
  53. package/dist/LinearGenomeView/components/RubberbandSpan.d.ts +14 -0
  54. package/dist/LinearGenomeView/components/RubberbandSpan.js +90 -0
  55. package/dist/LinearGenomeView/components/RubberbandSpan.js.map +1 -0
  56. package/dist/LinearGenomeView/components/{ScaleBar.d.ts → Scalebar.d.ts} +3 -3
  57. package/dist/LinearGenomeView/components/{ScaleBar.js → Scalebar.js} +11 -11
  58. package/dist/LinearGenomeView/components/{ScaleBar.js.map → Scalebar.js.map} +1 -1
  59. package/dist/LinearGenomeView/components/SearchBox.js +6 -6
  60. package/dist/LinearGenomeView/components/SearchBox.js.map +1 -1
  61. package/dist/LinearGenomeView/components/SearchResultsDialog.js +17 -31
  62. package/dist/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
  63. package/dist/LinearGenomeView/components/SequenceSearchDialog.js +4 -19
  64. package/dist/LinearGenomeView/components/SequenceSearchDialog.js.map +1 -1
  65. package/dist/LinearGenomeView/components/TrackContainer.d.ts +1 -1
  66. package/dist/LinearGenomeView/components/TrackContainer.js +13 -10
  67. package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -1
  68. package/dist/LinearGenomeView/components/TrackLabel.js +9 -1
  69. package/dist/LinearGenomeView/components/TrackLabel.js.map +1 -1
  70. package/dist/LinearGenomeView/components/TracksContainer.d.ts +1 -1
  71. package/dist/LinearGenomeView/components/TracksContainer.js +21 -118
  72. package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -1
  73. package/dist/LinearGenomeView/components/VerticalGuide.d.ts +9 -0
  74. package/dist/LinearGenomeView/components/VerticalGuide.js +29 -0
  75. package/dist/LinearGenomeView/components/VerticalGuide.js.map +1 -0
  76. package/dist/LinearGenomeView/components/hooks.d.ts +65 -0
  77. package/dist/LinearGenomeView/components/hooks.js +264 -0
  78. package/dist/LinearGenomeView/components/hooks.js.map +1 -0
  79. package/dist/LinearGenomeView/components/util.d.ts +5 -2
  80. package/dist/LinearGenomeView/components/util.js +7 -6
  81. package/dist/LinearGenomeView/components/util.js.map +1 -1
  82. package/dist/LinearGenomeView/index.d.ts +3 -453
  83. package/dist/LinearGenomeView/index.js +11 -1247
  84. package/dist/LinearGenomeView/index.js.map +1 -1
  85. package/dist/LinearGenomeView/model.d.ts +535 -0
  86. package/dist/LinearGenomeView/model.js +1357 -0
  87. package/dist/LinearGenomeView/model.js.map +1 -0
  88. package/dist/index.d.ts +20 -8
  89. package/dist/index.js +9 -72
  90. package/dist/index.js.map +1 -1
  91. package/esm/BaseLinearDisplay/components/Tooltip.d.ts +1 -1
  92. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +3 -3
  93. package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
  94. package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js +1 -1
  95. package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
  96. package/esm/BasicTrack/index.d.ts +1 -1
  97. package/esm/BasicTrack/index.js +4 -4
  98. package/esm/BasicTrack/index.js.map +1 -1
  99. package/esm/LaunchLinearGenomeView/index.d.ts +3 -0
  100. package/esm/LaunchLinearGenomeView/index.js +42 -0
  101. package/esm/LaunchLinearGenomeView/index.js.map +1 -0
  102. package/esm/LinearBareDisplay/index.d.ts +6 -2
  103. package/esm/LinearBareDisplay/index.js +18 -2
  104. package/esm/LinearBareDisplay/index.js.map +1 -1
  105. package/esm/LinearBasicDisplay/components/SetMaxHeight.js +3 -13
  106. package/esm/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
  107. package/esm/LinearBasicDisplay/index.d.ts +6 -2
  108. package/esm/LinearBasicDisplay/index.js +19 -2
  109. package/esm/LinearBasicDisplay/index.js.map +1 -1
  110. package/esm/LinearBasicDisplay/model.d.ts +21 -14
  111. package/esm/LinearBasicDisplay/model.js +2 -1
  112. package/esm/LinearBasicDisplay/model.js.map +1 -1
  113. package/esm/LinearGenomeView/components/CenterLine.d.ts +1 -1
  114. package/esm/LinearGenomeView/components/ExportSvgDialog.js +3 -18
  115. package/esm/LinearGenomeView/components/ExportSvgDialog.js.map +1 -1
  116. package/esm/LinearGenomeView/components/GetSequenceDialog.d.ts +1 -1
  117. package/esm/LinearGenomeView/components/GetSequenceDialog.js +8 -19
  118. package/esm/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
  119. package/esm/LinearGenomeView/components/Gridlines.d.ts +1 -1
  120. package/esm/LinearGenomeView/components/Header.d.ts +1 -1
  121. package/esm/LinearGenomeView/components/Header.js +2 -2
  122. package/esm/LinearGenomeView/components/HelpDialog.js +3 -18
  123. package/esm/LinearGenomeView/components/HelpDialog.js.map +1 -1
  124. package/esm/LinearGenomeView/components/ImportForm.d.ts +1 -1
  125. package/esm/LinearGenomeView/components/ImportForm.js +18 -16
  126. package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
  127. package/esm/LinearGenomeView/components/LinearGenomeView.d.ts +1 -1
  128. package/esm/LinearGenomeView/components/LinearGenomeView.js +2 -4
  129. package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
  130. package/esm/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +1 -1
  131. package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js +3 -3
  132. package/esm/LinearGenomeView/components/{OverviewRubberBand.d.ts → OverviewRubberband.d.ts} +3 -3
  133. package/esm/LinearGenomeView/components/{OverviewRubberBand.js → OverviewRubberband.js} +25 -80
  134. package/esm/LinearGenomeView/components/OverviewRubberband.js.map +1 -0
  135. package/{dist/LinearGenomeView/components/OverviewScaleBar.d.ts → esm/LinearGenomeView/components/OverviewScalebar.d.ts} +3 -3
  136. package/esm/LinearGenomeView/components/{OverviewScaleBar.js → OverviewScalebar.js} +25 -24
  137. package/esm/LinearGenomeView/components/OverviewScalebar.js.map +1 -0
  138. package/esm/LinearGenomeView/components/RefNameAutocomplete.js +1 -1
  139. package/esm/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
  140. package/esm/LinearGenomeView/components/{RubberBand.d.ts → Rubberband.d.ts} +3 -3
  141. package/esm/LinearGenomeView/components/Rubberband.js +29 -0
  142. package/esm/LinearGenomeView/components/Rubberband.js.map +1 -0
  143. package/esm/LinearGenomeView/components/RubberbandSpan.d.ts +14 -0
  144. package/esm/LinearGenomeView/components/RubberbandSpan.js +65 -0
  145. package/esm/LinearGenomeView/components/RubberbandSpan.js.map +1 -0
  146. package/esm/LinearGenomeView/components/{ScaleBar.d.ts → Scalebar.d.ts} +3 -3
  147. package/esm/LinearGenomeView/components/{ScaleBar.js → Scalebar.js} +11 -11
  148. package/esm/LinearGenomeView/components/{ScaleBar.js.map → Scalebar.js.map} +1 -1
  149. package/esm/LinearGenomeView/components/SearchBox.js +6 -6
  150. package/esm/LinearGenomeView/components/SearchBox.js.map +1 -1
  151. package/esm/LinearGenomeView/components/SearchResultsDialog.js +18 -32
  152. package/esm/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
  153. package/esm/LinearGenomeView/components/SequenceSearchDialog.js +5 -17
  154. package/esm/LinearGenomeView/components/SequenceSearchDialog.js.map +1 -1
  155. package/esm/LinearGenomeView/components/TrackContainer.d.ts +1 -1
  156. package/esm/LinearGenomeView/components/TrackContainer.js +14 -11
  157. package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -1
  158. package/esm/LinearGenomeView/components/TrackLabel.js +9 -1
  159. package/esm/LinearGenomeView/components/TrackLabel.js.map +1 -1
  160. package/esm/LinearGenomeView/components/TracksContainer.d.ts +1 -1
  161. package/esm/LinearGenomeView/components/TracksContainer.js +22 -119
  162. package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -1
  163. package/esm/LinearGenomeView/components/VerticalGuide.d.ts +9 -0
  164. package/esm/LinearGenomeView/components/VerticalGuide.js +24 -0
  165. package/esm/LinearGenomeView/components/VerticalGuide.js.map +1 -0
  166. package/esm/LinearGenomeView/components/hooks.d.ts +65 -0
  167. package/esm/LinearGenomeView/components/hooks.js +255 -0
  168. package/esm/LinearGenomeView/components/hooks.js.map +1 -0
  169. package/esm/LinearGenomeView/components/util.d.ts +5 -2
  170. package/esm/LinearGenomeView/components/util.js +4 -3
  171. package/esm/LinearGenomeView/components/util.js.map +1 -1
  172. package/esm/LinearGenomeView/index.d.ts +3 -453
  173. package/esm/LinearGenomeView/index.js +9 -1238
  174. package/esm/LinearGenomeView/index.js.map +1 -1
  175. package/esm/LinearGenomeView/model.d.ts +535 -0
  176. package/esm/LinearGenomeView/model.js +1322 -0
  177. package/esm/LinearGenomeView/model.js.map +1 -0
  178. package/esm/index.d.ts +20 -8
  179. package/esm/index.js +9 -72
  180. package/esm/index.js.map +1 -1
  181. package/package.json +3 -3
  182. package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +1 -1
  183. package/src/BasicTrack/index.ts +4 -8
  184. package/src/LaunchLinearGenomeView/index.ts +66 -0
  185. package/src/LinearBareDisplay/index.ts +21 -2
  186. package/src/LinearBasicDisplay/components/SetMaxHeight.tsx +3 -28
  187. package/src/LinearBasicDisplay/index.ts +23 -2
  188. package/src/LinearBasicDisplay/model.ts +2 -1
  189. package/src/LinearGenomeView/components/ExportSvgDialog.tsx +2 -23
  190. package/src/LinearGenomeView/components/GetSequenceDialog.tsx +13 -31
  191. package/src/LinearGenomeView/components/Header.tsx +3 -3
  192. package/src/LinearGenomeView/components/HelpDialog.tsx +8 -34
  193. package/src/LinearGenomeView/components/ImportForm.tsx +19 -16
  194. package/src/LinearGenomeView/components/LinearGenomeView.tsx +2 -8
  195. package/src/LinearGenomeView/components/LinearGenomeViewSvg.tsx +3 -3
  196. package/src/LinearGenomeView/components/{OverviewRubberBand.tsx → OverviewRubberband.tsx} +32 -114
  197. package/src/LinearGenomeView/components/{OverviewScaleBar.tsx → OverviewScalebar.tsx} +26 -25
  198. package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +2 -1
  199. package/src/LinearGenomeView/components/Rubberband.tsx +89 -0
  200. package/src/LinearGenomeView/components/RubberbandSpan.tsx +116 -0
  201. package/src/LinearGenomeView/components/{ScaleBar.test.tsx → Scalebar.test.tsx} +5 -5
  202. package/src/LinearGenomeView/components/{ScaleBar.tsx → Scalebar.tsx} +11 -11
  203. package/src/LinearGenomeView/components/SearchBox.tsx +6 -6
  204. package/src/LinearGenomeView/components/SearchResultsDialog.tsx +17 -44
  205. package/src/LinearGenomeView/components/SequenceSearchDialog.tsx +4 -30
  206. package/src/LinearGenomeView/components/TrackContainer.tsx +41 -28
  207. package/src/LinearGenomeView/components/TrackLabel.tsx +10 -1
  208. package/src/LinearGenomeView/components/TracksContainer.tsx +59 -136
  209. package/src/LinearGenomeView/components/VerticalGuide.tsx +37 -0
  210. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +37 -39
  211. package/src/LinearGenomeView/components/hooks.ts +300 -0
  212. package/src/LinearGenomeView/components/util.ts +8 -11
  213. package/src/LinearGenomeView/index.test.ts +6 -7
  214. package/src/LinearGenomeView/index.ts +17 -0
  215. package/src/LinearGenomeView/{index.tsx → model.ts} +159 -75
  216. package/src/index.ts +13 -108
  217. package/dist/LinearGenomeView/components/OverviewRubberBand.js.map +0 -1
  218. package/dist/LinearGenomeView/components/OverviewScaleBar.js.map +0 -1
  219. package/dist/LinearGenomeView/components/RubberBand.js +0 -221
  220. package/dist/LinearGenomeView/components/RubberBand.js.map +0 -1
  221. package/esm/LinearGenomeView/components/OverviewRubberBand.js.map +0 -1
  222. package/esm/LinearGenomeView/components/OverviewScaleBar.js.map +0 -1
  223. package/esm/LinearGenomeView/components/RubberBand.js +0 -196
  224. package/esm/LinearGenomeView/components/RubberBand.js.map +0 -1
  225. package/src/LinearGenomeView/components/RubberBand.tsx +0 -308
@@ -1,1241 +1,12 @@
1
1
  import { lazy } from 'react';
2
- import { getConf } from '@jbrowse/core/configuration';
3
- import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes/models';
4
- import { ElementId, Region as MUIRegion } from '@jbrowse/core/util/types/mst';
5
- import { ReturnToImportFormDialog } from '@jbrowse/core/ui';
6
- import { assembleLocString, clamp, findLastIndex, getContainingView, getSession, isViewContainer, isSessionModelWithWidgets, measureText, parseLocString, springAnimate, isSessionWithAddTracks, } from '@jbrowse/core/util';
7
- import calculateDynamicBlocks from '@jbrowse/core/util/calculateDynamicBlocks';
8
- import calculateStaticBlocks from '@jbrowse/core/util/calculateStaticBlocks';
9
- import { getParentRenderProps } from '@jbrowse/core/util/tracks';
10
- import { transaction, autorun } from 'mobx';
11
- import { addDisposer, cast, getSnapshot, getRoot, resolveIdentifier, types, } from 'mobx-state-tree';
12
- import Base1DView from '@jbrowse/core/util/Base1DViewModel';
13
- import { moveTo, pxToBp, bpToPx } from '@jbrowse/core/util/Base1DUtils';
14
- import { saveAs } from 'file-saver';
15
- import clone from 'clone';
16
- // icons
17
- import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons';
18
- import SyncAltIcon from '@mui/icons-material/SyncAlt';
19
- import VisibilityIcon from '@mui/icons-material/Visibility';
20
- import LabelIcon from '@mui/icons-material/Label';
21
- import FolderOpenIcon from '@mui/icons-material/FolderOpen';
22
- import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
23
- import ZoomInIcon from '@mui/icons-material/ZoomIn';
24
- import MenuOpenIcon from '@mui/icons-material/MenuOpen';
25
- // locals
26
- import { renderToSvg } from './components/LinearGenomeViewSvg';
27
- import RefNameAutocomplete from './components/RefNameAutocomplete';
28
- import SearchBox from './components/SearchBox';
29
- import ExportSvgDlg from './components/ExportSvgDialog';
30
- import MiniControls from './components/MiniControls';
31
- import Header from './components/Header';
32
- import ZoomControls from './components/ZoomControls';
33
- import LinearGenomeView from './components/LinearGenomeView';
34
- const SequenceSearchDialog = lazy(() => import('./components/SequenceSearchDialog'));
35
- function calculateVisibleLocStrings(contentBlocks) {
36
- if (!contentBlocks.length) {
37
- return '';
38
- }
39
- const isSingleAssemblyName = contentBlocks.every(b => b.assemblyName === contentBlocks[0].assemblyName);
40
- const locs = contentBlocks.map(block => assembleLocString({
41
- ...block,
42
- start: Math.round(block.start),
43
- end: Math.round(block.end),
44
- assemblyName: isSingleAssemblyName ? undefined : block.assemblyName,
2
+ import { ViewType } from '@jbrowse/core/pluggableElementTypes';
3
+ import { stateModelFactory } from './model';
4
+ export default (pluginManager) => {
5
+ pluginManager.addViewType(() => new ViewType({
6
+ name: 'LinearGenomeView',
7
+ stateModel: stateModelFactory(pluginManager),
8
+ ReactComponent: lazy(() => import('./components/LinearGenomeView')),
45
9
  }));
46
- return locs.join(' ');
47
- }
48
- export const HEADER_BAR_HEIGHT = 48;
49
- export const HEADER_OVERVIEW_HEIGHT = 20;
50
- export const SCALE_BAR_HEIGHT = 17;
51
- export const RESIZE_HANDLE_HEIGHT = 3;
52
- export const INTER_REGION_PADDING_WIDTH = 2;
53
- export const SPACING = 7;
54
- export const WIDGET_HEIGHT = 32;
55
- function localStorageGetItem(item) {
56
- return typeof localStorage !== 'undefined'
57
- ? localStorage.getItem(item)
58
- : undefined;
59
- }
60
- /**
61
- * #stateModel LinearGenomeView
62
- */
63
- export function stateModelFactory(pluginManager) {
64
- return types
65
- .compose(BaseViewModel, types.model('LinearGenomeView', {
66
- /**
67
- * #property
68
- */
69
- id: ElementId,
70
- /**
71
- * #property
72
- */
73
- type: types.literal('LinearGenomeView'),
74
- /**
75
- * #property
76
- * corresponds roughly to the horizontal scroll of the LGV
77
- */
78
- offsetPx: 0,
79
- /**
80
- * #property
81
- * corresponds roughly to the zoom level, base-pairs per pixel
82
- */
83
- bpPerPx: 1,
84
- /**
85
- * #property
86
- * currently displayed regions, can be a single chromosome, arbitrary subsections,
87
- * or the entire set of chromosomes in the genome, but it not advised to use the
88
- * entire set of chromosomes if your assembly is very fragmented
89
- */
90
- displayedRegions: types.array(MUIRegion),
91
- /**
92
- * #property
93
- * array of currently displayed tracks state models instances
94
- */
95
- tracks: types.array(pluginManager.pluggableMstType('track', 'stateModel')),
96
- /**
97
- * #property
98
- * array of currently displayed tracks state model's
99
- */
100
- hideHeader: false,
101
- /**
102
- * #property
103
- */
104
- hideHeaderOverview: false,
105
- /**
106
- * #property
107
- */
108
- hideNoTracksActive: false,
109
- /**
110
- * #property
111
- */
112
- trackSelectorType: types.optional(types.enumeration(['hierarchical']), 'hierarchical'),
113
- /**
114
- * #property
115
- * how to display the track labels, can be "overlapping", "offset", or "hidden"
116
- */
117
- trackLabels: types.optional(types.string, () => localStorageGetItem('lgv-trackLabels') || 'overlapping'),
118
- /**
119
- * #property
120
- * show the "center line"
121
- */
122
- showCenterLine: types.optional(types.boolean, () => {
123
- const setting = localStorageGetItem('lgv-showCenterLine');
124
- return setting !== undefined && setting !== null ? !!+setting : false;
125
- }),
126
- /**
127
- * #property
128
- * show the "cytobands" in the overview scale bar
129
- */
130
- showCytobandsSetting: types.optional(types.boolean, () => {
131
- const setting = localStorageGetItem('lgv-showCytobands');
132
- return setting !== undefined && setting !== null ? !!+setting : true;
133
- }),
134
- /**
135
- * #property
136
- * show the "gridlines" in the track area
137
- */
138
- showGridlines: true,
139
- }))
140
- .volatile(() => ({
141
- volatileWidth: undefined,
142
- minimumBlockWidth: 3,
143
- draggingTrackId: undefined,
144
- volatileError: undefined,
145
- // array of callbacks to run after the next set of the displayedRegions,
146
- // which is basically like an onLoad
147
- afterDisplayedRegionsSetCallbacks: [],
148
- scaleFactor: 1,
149
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
- trackRefs: {},
151
- coarseDynamicBlocks: [],
152
- coarseTotalBp: 0,
153
- leftOffset: undefined,
154
- rightOffset: undefined,
155
- searchResults: undefined,
156
- searchQuery: undefined,
157
- seqDialogDisplayed: false,
158
- }))
159
- .views(self => ({
160
- /**
161
- * #getter
162
- */
163
- get width() {
164
- if (self.volatileWidth === undefined) {
165
- throw new Error('width undefined, make sure to check for model.initialized');
166
- }
167
- return self.volatileWidth;
168
- },
169
- /**
170
- * #getter
171
- */
172
- get interRegionPaddingWidth() {
173
- return INTER_REGION_PADDING_WIDTH;
174
- },
175
- /**
176
- * #getter
177
- */
178
- get assemblyNames() {
179
- return [
180
- ...new Set(self.displayedRegions.map(region => region.assemblyName)),
181
- ];
182
- },
183
- }))
184
- .views(self => ({
185
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
186
- MiniControlsComponent() {
187
- return MiniControls;
188
- },
189
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
190
- HeaderComponent() {
191
- return Header;
192
- },
193
- get assemblyErrors() {
194
- const { assemblyManager } = getSession(self);
195
- const { assemblyNames } = self;
196
- return assemblyNames
197
- .map(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.error; })
198
- .filter(f => !!f)
199
- .join(', ');
200
- },
201
- get assembliesInitialized() {
202
- const { assemblyManager } = getSession(self);
203
- const { assemblyNames } = self;
204
- return assemblyNames.every(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.initialized; });
205
- },
206
- get initialized() {
207
- return self.volatileWidth !== undefined && this.assembliesInitialized;
208
- },
209
- get hasDisplayedRegions() {
210
- return self.displayedRegions.length > 0;
211
- },
212
- get isSearchDialogDisplayed() {
213
- return self.searchResults !== undefined;
214
- },
215
- get scaleBarHeight() {
216
- return SCALE_BAR_HEIGHT + RESIZE_HANDLE_HEIGHT;
217
- },
218
- get headerHeight() {
219
- if (self.hideHeader) {
220
- return 0;
221
- }
222
- if (self.hideHeaderOverview) {
223
- return HEADER_BAR_HEIGHT;
224
- }
225
- return HEADER_BAR_HEIGHT + HEADER_OVERVIEW_HEIGHT;
226
- },
227
- get trackHeights() {
228
- return self.tracks
229
- .map(t => t.displays[0].height)
230
- .reduce((a, b) => a + b, 0);
231
- },
232
- get trackHeightsWithResizeHandles() {
233
- return this.trackHeights + self.tracks.length * RESIZE_HANDLE_HEIGHT;
234
- },
235
- get height() {
236
- return (this.trackHeightsWithResizeHandles +
237
- this.headerHeight +
238
- this.scaleBarHeight);
239
- },
240
- get totalBp() {
241
- return self.displayedRegions.reduce((a, b) => a + b.end - b.start, 0);
242
- },
243
- get maxBpPerPx() {
244
- return this.totalBp / (self.width * 0.9);
245
- },
246
- get minBpPerPx() {
247
- return 1 / 50;
248
- },
249
- get error() {
250
- return self.volatileError || this.assemblyErrors;
251
- },
252
- get maxOffset() {
253
- // objectively determined to keep the linear genome on the main screen
254
- const leftPadding = 10;
255
- return this.displayedRegionsTotalPx - leftPadding;
256
- },
257
- get minOffset() {
258
- // objectively determined to keep the linear genome on the main screen
259
- const rightPadding = 30;
260
- return -self.width + rightPadding;
261
- },
262
- get displayedRegionsTotalPx() {
263
- return this.totalBp / self.bpPerPx;
264
- },
265
- renderProps() {
266
- return {
267
- ...getParentRenderProps(self),
268
- bpPerPx: self.bpPerPx,
269
- highResolutionScaling: getConf(getSession(self), 'highResolutionScaling'),
270
- };
271
- },
272
- searchScope(assemblyName) {
273
- return {
274
- assemblyName,
275
- includeAggregateIndexes: true,
276
- tracks: self.tracks,
277
- };
278
- },
279
- getTrack(id) {
280
- return self.tracks.find(t => t.configuration.trackId === id);
281
- },
282
- rankSearchResults(results) {
283
- // order of rank
284
- const openTrackIds = self.tracks.map(track => track.configuration.trackId);
285
- results.forEach(result => {
286
- if (openTrackIds.includes(result.trackId)) {
287
- result.updateScore(result.getScore() + 1);
288
- }
289
- });
290
- return results;
291
- },
292
- // modifies view menu action onClick to apply to all tracks of same type
293
- rewriteOnClicks(trackType, viewMenuActions) {
294
- viewMenuActions.forEach(action => {
295
- // go to lowest level menu
296
- if ('subMenu' in action) {
297
- this.rewriteOnClicks(trackType, action.subMenu);
298
- }
299
- if ('onClick' in action) {
300
- const holdOnClick = action.onClick;
301
- action.onClick = (...args) => {
302
- self.tracks.forEach(track => {
303
- if (track.type === trackType) {
304
- holdOnClick.apply(track, [track, ...args]);
305
- }
306
- });
307
- };
308
- }
309
- });
310
- },
311
- get trackTypeActions() {
312
- const allActions = new Map();
313
- self.tracks.forEach(track => {
314
- const trackInMap = allActions.get(track.type);
315
- if (!trackInMap) {
316
- const viewMenuActions = clone(track.viewMenuActions);
317
- this.rewriteOnClicks(track.type, viewMenuActions);
318
- allActions.set(track.type, viewMenuActions);
319
- }
320
- });
321
- return allActions;
322
- },
323
- }))
324
- .actions(self => ({
325
- /**
326
- * #action
327
- */
328
- setShowCytobands(flag) {
329
- self.showCytobandsSetting = flag;
330
- localStorage.setItem('lgv-showCytobands', `${+flag}`);
331
- },
332
- /**
333
- * #action
334
- */
335
- setWidth(newWidth) {
336
- self.volatileWidth = newWidth;
337
- },
338
- /**
339
- * #action
340
- */
341
- setError(error) {
342
- self.volatileError = error;
343
- },
344
- /**
345
- * #action
346
- */
347
- toggleHeader() {
348
- self.hideHeader = !self.hideHeader;
349
- },
350
- /**
351
- * #action
352
- */
353
- toggleHeaderOverview() {
354
- self.hideHeaderOverview = !self.hideHeaderOverview;
355
- },
356
- /**
357
- * #action
358
- */
359
- toggleNoTracksActive() {
360
- self.hideNoTracksActive = !self.hideNoTracksActive;
361
- },
362
- /**
363
- * #action
364
- */
365
- toggleShowGridlines() {
366
- self.showGridlines = !self.showGridlines;
367
- },
368
- /**
369
- * #action
370
- */
371
- scrollTo(offsetPx) {
372
- const newOffsetPx = clamp(offsetPx, self.minOffset, self.maxOffset);
373
- self.offsetPx = newOffsetPx;
374
- return newOffsetPx;
375
- },
376
- /**
377
- * #action
378
- */
379
- zoomTo(bpPerPx) {
380
- const newBpPerPx = clamp(bpPerPx, self.minBpPerPx, self.maxBpPerPx);
381
- if (newBpPerPx === self.bpPerPx) {
382
- return newBpPerPx;
383
- }
384
- const oldBpPerPx = self.bpPerPx;
385
- self.bpPerPx = newBpPerPx;
386
- if (Math.abs(oldBpPerPx - newBpPerPx) < 0.000001) {
387
- console.warn('zoomTo bpPerPx rounding error');
388
- return oldBpPerPx;
389
- }
390
- // tweak the offset so that the center of the view remains at the same coordinate
391
- const viewWidth = self.width;
392
- this.scrollTo(Math.round(((self.offsetPx + viewWidth / 2) * oldBpPerPx) / newBpPerPx -
393
- viewWidth / 2));
394
- return newBpPerPx;
395
- },
396
- /**
397
- * #action
398
- * sets offsets used in the get sequence dialog
399
- */
400
- setOffsets(left, right) {
401
- self.leftOffset = left;
402
- self.rightOffset = right;
403
- },
404
- /**
405
- * #action
406
- */
407
- setSearchResults(results, query) {
408
- self.searchResults = results;
409
- self.searchQuery = query;
410
- },
411
- /**
412
- * #action
413
- */
414
- setGetSequenceDialogOpen(open) {
415
- self.seqDialogDisplayed = open;
416
- },
417
- /**
418
- * #action
419
- */
420
- setNewView(bpPerPx, offsetPx) {
421
- this.zoomTo(bpPerPx);
422
- this.scrollTo(offsetPx);
423
- },
424
- /**
425
- * #action
426
- */
427
- horizontallyFlip() {
428
- self.displayedRegions = cast(self.displayedRegions
429
- .slice()
430
- .reverse()
431
- .map(region => ({ ...region, reversed: !region.reversed })));
432
- this.scrollTo(self.totalBp / self.bpPerPx - self.offsetPx - self.width);
433
- },
434
- /**
435
- * #action
436
- */
437
- showTrack(trackId, initialSnapshot = {}, displayInitialSnapshot = {}) {
438
- const schema = pluginManager.pluggableConfigSchemaType('track');
439
- const conf = resolveIdentifier(schema, getRoot(self), trackId);
440
- if (!conf) {
441
- throw new Error(`Could not resolve identifier "${trackId}"`);
442
- }
443
- const trackType = pluginManager.getTrackType(conf === null || conf === void 0 ? void 0 : conf.type);
444
- if (!trackType) {
445
- throw new Error(`Unknown track type ${conf.type}`);
446
- }
447
- const viewType = pluginManager.getViewType(self.type);
448
- const supportedDisplays = viewType.displayTypes.map(d => d.name);
449
- const displayConf = conf.displays.find((d) => supportedDisplays.includes(d.type));
450
- if (!displayConf) {
451
- throw new Error(`Could not find a compatible display for view type ${self.type}`);
452
- }
453
- const t = self.tracks.filter(t => t.configuration === conf);
454
- if (t.length === 0) {
455
- const track = trackType.stateModel.create({
456
- ...initialSnapshot,
457
- type: conf.type,
458
- configuration: conf,
459
- displays: [
460
- {
461
- type: displayConf.type,
462
- configuration: displayConf,
463
- ...displayInitialSnapshot,
464
- },
465
- ],
466
- });
467
- self.tracks.push(track);
468
- return track;
469
- }
470
- return t[0];
471
- },
472
- hideTrack(trackId) {
473
- const schema = pluginManager.pluggableConfigSchemaType('track');
474
- const conf = resolveIdentifier(schema, getRoot(self), trackId);
475
- const t = self.tracks.filter(t => t.configuration === conf);
476
- transaction(() => t.forEach(t => self.tracks.remove(t)));
477
- return t.length;
478
- },
479
- }))
480
- .actions(self => ({
481
- /**
482
- * #action
483
- */
484
- moveTrack(movingId, targetId) {
485
- const oldIndex = self.tracks.findIndex(track => track.id === movingId);
486
- if (oldIndex === -1) {
487
- throw new Error(`Track ID ${movingId} not found`);
488
- }
489
- const newIndex = self.tracks.findIndex(track => track.id === targetId);
490
- if (newIndex === -1) {
491
- throw new Error(`Track ID ${targetId} not found`);
492
- }
493
- const track = getSnapshot(self.tracks[oldIndex]);
494
- self.tracks.splice(oldIndex, 1);
495
- self.tracks.splice(newIndex, 0, track);
496
- },
497
- /**
498
- * #action
499
- */
500
- closeView() {
501
- const parent = getContainingView(self);
502
- if (parent) {
503
- // I am embedded in a some other view
504
- if (isViewContainer(parent)) {
505
- parent.removeView(self);
506
- }
507
- }
508
- else {
509
- // I am part of a session
510
- getSession(self).removeView(self);
511
- }
512
- },
513
- /**
514
- * #action
515
- */
516
- toggleTrack(trackId) {
517
- // if we have any tracks with that configuration, turn them off
518
- const hiddenCount = self.hideTrack(trackId);
519
- // if none had that configuration, turn one on
520
- if (!hiddenCount) {
521
- self.showTrack(trackId);
522
- }
523
- },
524
- /**
525
- * #action
526
- */
527
- setTrackLabels(setting) {
528
- self.trackLabels = setting;
529
- localStorage.setItem('lgv-trackLabels', setting);
530
- },
531
- /**
532
- * #action
533
- */
534
- toggleCenterLine() {
535
- self.showCenterLine = !self.showCenterLine;
536
- localStorage.setItem('lgv-showCenterLine', `${+self.showCenterLine}`);
537
- },
538
- /**
539
- * #action
540
- */
541
- setDisplayedRegions(regions) {
542
- self.displayedRegions = cast(regions);
543
- self.zoomTo(self.bpPerPx);
544
- },
545
- /**
546
- * #action
547
- */
548
- activateTrackSelector() {
549
- if (self.trackSelectorType === 'hierarchical') {
550
- const session = getSession(self);
551
- if (isSessionModelWithWidgets(session)) {
552
- const selector = session.addWidget('HierarchicalTrackSelectorWidget', 'hierarchicalTrackSelector', { view: self });
553
- session.showWidget(selector);
554
- return selector;
555
- }
556
- }
557
- throw new Error(`invalid track selector type ${self.trackSelectorType}`);
558
- },
559
- /**
560
- * #method
561
- * Helper method for the fetchSequence.
562
- * Retrieves the corresponding regions that were selected by the rubberband
563
- *
564
- * @param leftOffset - `object as {start, end, index, offset}`, offset = start of user drag
565
- * @param rightOffset - `object as {start, end, index, offset}`, offset = end of user drag
566
- * @returns array of Region[]
567
- */
568
- getSelectedRegions(leftOffset, rightOffset) {
569
- const snap = getSnapshot(self);
570
- const simView = Base1DView.create({
571
- ...snap,
572
- interRegionPaddingWidth: self.interRegionPaddingWidth,
573
- });
574
- simView.setVolatileWidth(self.width);
575
- simView.moveTo(leftOffset, rightOffset);
576
- return simView.dynamicBlocks.contentBlocks.map(region => ({
577
- ...region,
578
- start: Math.floor(region.start),
579
- end: Math.ceil(region.end),
580
- }));
581
- },
582
- /**
583
- * #action
584
- * schedule something to be run after the next time displayedRegions is set
585
- */
586
- afterDisplayedRegionsSet(cb) {
587
- self.afterDisplayedRegionsSetCallbacks.push(cb);
588
- },
589
- /**
590
- * #action
591
- */
592
- horizontalScroll(distance) {
593
- const oldOffsetPx = self.offsetPx;
594
- // newOffsetPx is the actual offset after the scroll is clamped
595
- const newOffsetPx = self.scrollTo(self.offsetPx + distance);
596
- return newOffsetPx - oldOffsetPx;
597
- },
598
- /**
599
- * #action
600
- */
601
- center() {
602
- const centerBp = self.totalBp / 2;
603
- const centerPx = centerBp / self.bpPerPx;
604
- self.scrollTo(Math.round(centerPx - self.width / 2));
605
- },
606
- /**
607
- * #action
608
- */
609
- showAllRegions() {
610
- self.zoomTo(self.maxBpPerPx);
611
- this.center();
612
- },
613
- /**
614
- * #action
615
- */
616
- showAllRegionsInAssembly(assemblyName) {
617
- const session = getSession(self);
618
- const { assemblyManager } = session;
619
- if (!assemblyName) {
620
- const names = new Set(self.displayedRegions.map(r => r.assemblyName));
621
- if (names.size > 1) {
622
- session.notify(`Can't perform operation with multiple assemblies currently`);
623
- return;
624
- }
625
- ;
626
- [assemblyName] = [...names];
627
- }
628
- const assembly = assemblyManager.get(assemblyName);
629
- if (assembly) {
630
- const { regions } = assembly;
631
- if (regions) {
632
- this.setDisplayedRegions(regions);
633
- self.zoomTo(self.maxBpPerPx);
634
- this.center();
635
- }
636
- }
637
- },
638
- /**
639
- * #action
640
- */
641
- setDraggingTrackId(idx) {
642
- self.draggingTrackId = idx;
643
- },
644
- /**
645
- * #action
646
- */
647
- setScaleFactor(factor) {
648
- self.scaleFactor = factor;
649
- },
650
- /**
651
- * #action
652
- * this "clears the view" and makes the view return to the import form
653
- */
654
- clearView() {
655
- this.setDisplayedRegions([]);
656
- self.tracks.clear();
657
- // it is necessary to run these after setting displayed regions empty
658
- // or else model.offsetPx gets set to Infinity and breaks
659
- // mobx-state-tree snapshot
660
- self.scrollTo(0);
661
- self.zoomTo(10);
662
- },
663
- /**
664
- * #action
665
- * creates an svg export and save using FileSaver
666
- */
667
- async exportSvg(opts = {}) {
668
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
669
- const html = await renderToSvg(self, opts);
670
- const blob = new Blob([html], { type: 'image/svg+xml' });
671
- saveAs(blob, opts.filename || 'image.svg');
672
- },
673
- }))
674
- .actions(self => {
675
- let cancelLastAnimation = () => { };
676
- /**
677
- * #action
678
- * perform animated slide
679
- */
680
- function slide(viewWidths) {
681
- const [animate, cancelAnimation] = springAnimate(self.offsetPx, self.offsetPx + self.width * viewWidths, self.scrollTo);
682
- cancelLastAnimation();
683
- cancelLastAnimation = cancelAnimation;
684
- animate();
685
- }
686
- return { slide };
687
- })
688
- .actions(self => {
689
- let cancelLastAnimation = () => { };
690
- /**
691
- * #action
692
- * perform animated zoom
693
- */
694
- function zoom(targetBpPerPx) {
695
- self.zoomTo(self.bpPerPx);
696
- if (
697
- // already zoomed all the way in
698
- (targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx) ||
699
- // already zoomed all the way out
700
- (targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx)) {
701
- return;
702
- }
703
- const factor = self.bpPerPx / targetBpPerPx;
704
- const [animate, cancelAnimation] = springAnimate(1, factor, self.setScaleFactor, () => {
705
- self.zoomTo(targetBpPerPx);
706
- self.setScaleFactor(1);
707
- });
708
- cancelLastAnimation();
709
- cancelLastAnimation = cancelAnimation;
710
- animate();
711
- }
712
- return { zoom };
713
- })
714
- .views(self => ({
715
- /**
716
- * #getter
717
- */
718
- get canShowCytobands() {
719
- return self.displayedRegions.length === 1 && this.anyCytobandsExist;
720
- },
721
- /**
722
- * #getter
723
- */
724
- get showCytobands() {
725
- return this.canShowCytobands && self.showCytobandsSetting;
726
- },
727
- /**
728
- * #getter
729
- */
730
- get anyCytobandsExist() {
731
- const { assemblyManager } = getSession(self);
732
- return self.assemblyNames.some(a => { var _a, _b; return (_b = (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.cytobands) === null || _b === void 0 ? void 0 : _b.length; });
733
- },
734
- /**
735
- * #getter
736
- * the cytoband is displayed to the right of the chromosome name,
737
- * and that offset is calculated manually with this method
738
- */
739
- get cytobandOffset() {
740
- return this.showCytobands
741
- ? measureText(self.displayedRegions[0].refName, 12) + 15
742
- : 0;
743
- },
744
- }))
745
- .views(self => ({
746
- /**
747
- * #method
748
- * return the view menu items
749
- */
750
- menuItems() {
751
- const { canShowCytobands, showCytobands } = self;
752
- const session = getSession(self);
753
- const menuItems = [
754
- {
755
- label: 'Return to import form',
756
- onClick: () => {
757
- getSession(self).queueDialog(handleClose => [
758
- ReturnToImportFormDialog,
759
- { model: self, handleClose },
760
- ]);
761
- },
762
- icon: FolderOpenIcon,
763
- },
764
- ...(isSessionWithAddTracks(session)
765
- ? [
766
- {
767
- label: 'Sequence search',
768
- onClick: () => {
769
- getSession(self).queueDialog(handleClose => [
770
- SequenceSearchDialog,
771
- { model: self, handleClose },
772
- ]);
773
- },
774
- },
775
- ]
776
- : []),
777
- {
778
- label: 'Export SVG',
779
- icon: PhotoCameraIcon,
780
- onClick: () => {
781
- getSession(self).queueDialog(handleClose => [
782
- ExportSvgDlg,
783
- { model: self, handleClose },
784
- ]);
785
- },
786
- },
787
- {
788
- label: 'Open track selector',
789
- onClick: self.activateTrackSelector,
790
- icon: TrackSelectorIcon,
791
- },
792
- {
793
- label: 'Horizontally flip',
794
- icon: SyncAltIcon,
795
- onClick: self.horizontallyFlip,
796
- },
797
- { type: 'divider' },
798
- {
799
- label: 'Show all regions in assembly',
800
- icon: VisibilityIcon,
801
- onClick: self.showAllRegionsInAssembly,
802
- },
803
- {
804
- label: 'Show center line',
805
- icon: VisibilityIcon,
806
- type: 'checkbox',
807
- checked: self.showCenterLine,
808
- onClick: self.toggleCenterLine,
809
- },
810
- {
811
- label: 'Show header',
812
- icon: VisibilityIcon,
813
- type: 'checkbox',
814
- checked: !self.hideHeader,
815
- onClick: self.toggleHeader,
816
- },
817
- {
818
- label: 'Show header overview',
819
- icon: VisibilityIcon,
820
- type: 'checkbox',
821
- checked: !self.hideHeaderOverview,
822
- onClick: self.toggleHeaderOverview,
823
- disabled: self.hideHeader,
824
- },
825
- {
826
- label: 'Show no tracks active button',
827
- icon: VisibilityIcon,
828
- type: 'checkbox',
829
- checked: !self.hideNoTracksActive,
830
- onClick: self.toggleNoTracksActive,
831
- },
832
- {
833
- label: 'Show guidelines',
834
- icon: VisibilityIcon,
835
- type: 'checkbox',
836
- checked: self.showGridlines,
837
- onClick: self.toggleShowGridlines,
838
- },
839
- ...(canShowCytobands
840
- ? [
841
- {
842
- label: 'Show ideogram',
843
- icon: VisibilityIcon,
844
- type: 'checkbox',
845
- checked: self.showCytobands,
846
- onClick: () => self.setShowCytobands(!showCytobands),
847
- },
848
- ]
849
- : []),
850
- {
851
- label: 'Track labels',
852
- icon: LabelIcon,
853
- subMenu: [
854
- {
855
- label: 'Overlapping',
856
- icon: VisibilityIcon,
857
- type: 'radio',
858
- checked: self.trackLabels === 'overlapping',
859
- onClick: () => self.setTrackLabels('overlapping'),
860
- },
861
- {
862
- label: 'Offset',
863
- icon: VisibilityIcon,
864
- type: 'radio',
865
- checked: self.trackLabels === 'offset',
866
- onClick: () => self.setTrackLabels('offset'),
867
- },
868
- {
869
- label: 'Hidden',
870
- icon: VisibilityIcon,
871
- type: 'radio',
872
- checked: self.trackLabels === 'hidden',
873
- onClick: () => self.setTrackLabels('hidden'),
874
- },
875
- ],
876
- },
877
- ];
878
- // add track's view level menu options
879
- for (const [key, value] of self.trackTypeActions.entries()) {
880
- if (value.length) {
881
- menuItems.push({ type: 'divider' }, { type: 'subHeader', label: key });
882
- value.forEach(action => menuItems.push(action));
883
- }
884
- }
885
- return menuItems;
886
- },
887
- }))
888
- .views(self => {
889
- let currentlyCalculatedStaticBlocks;
890
- let stringifiedCurrentlyCalculatedStaticBlocks = '';
891
- return {
892
- /**
893
- * #getter
894
- * static blocks are an important concept jbrowse uses to avoid
895
- * re-rendering when you scroll to the side. when you horizontally
896
- * scroll to the right, old blocks to the left may be removed, and
897
- * new blocks may be instantiated on the right. tracks may use the
898
- * static blocks to render their data for the region represented by
899
- * the block
900
- */
901
- get staticBlocks() {
902
- const ret = calculateStaticBlocks(self);
903
- const sret = JSON.stringify(ret);
904
- if (stringifiedCurrentlyCalculatedStaticBlocks !== sret) {
905
- currentlyCalculatedStaticBlocks = ret;
906
- stringifiedCurrentlyCalculatedStaticBlocks = sret;
907
- }
908
- return currentlyCalculatedStaticBlocks;
909
- },
910
- /**
911
- * #getter
912
- * dynamic blocks represent the exact coordinates of the currently
913
- * visible genome regions on the screen. they are similar to static
914
- * blocks, but statcic blocks can go offscreen while dynamic blocks
915
- * represent exactly what is on screen
916
- */
917
- get dynamicBlocks() {
918
- return calculateDynamicBlocks(self);
919
- },
920
- /**
921
- * #getter
922
- * rounded dynamic blocks are dynamic blocks without fractions of bp
923
- */
924
- get roundedDynamicBlocks() {
925
- return this.dynamicBlocks.contentBlocks.map(block => ({
926
- ...block,
927
- start: Math.floor(block.start),
928
- end: Math.ceil(block.end),
929
- }));
930
- },
931
- /**
932
- * #getter
933
- * a single "combo-locstring" representing all the regions visible
934
- * on the screen
935
- */
936
- get visibleLocStrings() {
937
- return calculateVisibleLocStrings(this.dynamicBlocks.contentBlocks);
938
- },
939
- /**
940
- * #getter
941
- * same as visibleLocStrings, but only updated every 300ms
942
- */
943
- get coarseVisibleLocStrings() {
944
- return calculateVisibleLocStrings(self.coarseDynamicBlocks);
945
- },
946
- };
947
- })
948
- .actions(self => ({
949
- /**
950
- * #action
951
- */
952
- setCoarseDynamicBlocks(blocks) {
953
- self.coarseDynamicBlocks = blocks.contentBlocks;
954
- self.coarseTotalBp = blocks.totalBp;
955
- },
956
- afterAttach() {
957
- addDisposer(self, autorun(() => {
958
- if (self.initialized) {
959
- this.setCoarseDynamicBlocks(self.dynamicBlocks);
960
- }
961
- }, { delay: 150 }));
962
- },
963
- }))
964
- .actions(self => ({
965
- /**
966
- * #action
967
- * offset is the base-pair-offset in the displayed region, index is the index of the
968
- * displayed region in the linear genome view
969
- *
970
- * @param start - object as `{start, end, offset, index}`
971
- * @param end - object as `{start, end, offset, index}`
972
- */
973
- moveTo(start, end) {
974
- moveTo(self, start, end);
975
- },
976
- /**
977
- * #action
978
- * navigate to the given locstring
979
- *
980
- * @param locString - e.g. "chr1:1-100"
981
- * @param optAssemblyName - (optional) the assembly name to use when navigating to the locstring
982
- */
983
- async navToLocString(locString, optAssemblyName) {
984
- const { assemblyNames } = self;
985
- const { assemblyManager } = getSession(self);
986
- const { isValidRefName } = assemblyManager;
987
- const assemblyName = optAssemblyName || assemblyNames[0];
988
- let parsedLocStrings;
989
- const inputs = locString
990
- .split(/(\s+)/)
991
- .map(f => f.trim())
992
- .filter(f => !!f);
993
- if (assemblyName) {
994
- await assemblyManager.waitForAssembly(assemblyName);
995
- }
996
- // first try interpreting as a whitespace-separated sequence of
997
- // multiple locstrings
998
- try {
999
- parsedLocStrings = inputs.map(l => parseLocString(l, ref => isValidRefName(ref, assemblyName)));
1000
- }
1001
- catch (e) {
1002
- // if this fails, try interpreting as a whitespace-separated refname,
1003
- // start, end if start and end are integer inputs
1004
- const [refName, start, end] = inputs;
1005
- if (`${e}`.match(/Unknown reference sequence/) &&
1006
- Number.isInteger(+start) &&
1007
- Number.isInteger(+end)) {
1008
- parsedLocStrings = [
1009
- parseLocString(refName + ':' + start + '..' + end, ref => isValidRefName(ref, assemblyName)),
1010
- ];
1011
- }
1012
- else {
1013
- throw e;
1014
- }
1015
- }
1016
- const locations = await Promise.all(parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(async (region) => {
1017
- const asmName = region.assemblyName || assemblyName;
1018
- const asm = await assemblyManager.waitForAssembly(asmName);
1019
- const { refName } = region;
1020
- if (!asm) {
1021
- throw new Error(`assembly ${asmName} not found`);
1022
- }
1023
- const { regions } = asm;
1024
- if (!regions) {
1025
- throw new Error(`regions not loaded yet for ${asmName}`);
1026
- }
1027
- const canonicalRefName = asm.getCanonicalRefName(region.refName);
1028
- if (!canonicalRefName) {
1029
- throw new Error(`Could not find refName ${refName} in ${asm.name}`);
1030
- }
1031
- const parentRegion = regions.find(r => r.refName === canonicalRefName);
1032
- if (!parentRegion) {
1033
- throw new Error(`Could not find refName ${refName} in ${asmName}`);
1034
- }
1035
- return {
1036
- ...region,
1037
- assemblyName: asmName,
1038
- parentRegion,
1039
- };
1040
- }));
1041
- if (locations.length === 1) {
1042
- const loc = locations[0];
1043
- self.setDisplayedRegions([
1044
- { reversed: loc.reversed, ...loc.parentRegion },
1045
- ]);
1046
- const { start, end, parentRegion } = loc;
1047
- this.navTo({
1048
- ...loc,
1049
- start: clamp(start !== null && start !== void 0 ? start : 0, 0, parentRegion.end),
1050
- end: clamp(end !== null && end !== void 0 ? end : parentRegion.end, 0, parentRegion.end),
1051
- });
1052
- }
1053
- else {
1054
- self.setDisplayedRegions(
1055
- // @ts-ignore
1056
- locations.map(r => (r.start === undefined ? r.parentRegion : r)));
1057
- self.showAllRegions();
1058
- }
1059
- },
1060
- /**
1061
- * #action
1062
- * Navigate to a location based on its refName and optionally start, end,
1063
- * and assemblyName. Can handle if there are multiple displayedRegions
1064
- * from same refName. Only navigates to a location if it is entirely
1065
- * within a displayedRegion. Navigates to the first matching location
1066
- * encountered.
1067
- *
1068
- * Throws an error if navigation was unsuccessful
1069
- *
1070
- * @param query - a proposed location to navigate to
1071
- */
1072
- navTo(query) {
1073
- this.navToMultiple([query]);
1074
- },
1075
- /**
1076
- * #action
1077
- */
1078
- navToMultiple(locations) {
1079
- const firstLocation = locations[0];
1080
- let { refName } = firstLocation;
1081
- const { start, end, assemblyName = self.assemblyNames[0], } = firstLocation;
1082
- if (start !== undefined && end !== undefined && start > end) {
1083
- throw new Error(`start "${start + 1}" is greater than end "${end}"`);
1084
- }
1085
- const session = getSession(self);
1086
- const { assemblyManager } = session;
1087
- const assembly = assemblyManager.get(assemblyName);
1088
- if (assembly) {
1089
- const canonicalRefName = assembly.getCanonicalRefName(refName);
1090
- if (canonicalRefName) {
1091
- refName = canonicalRefName;
1092
- }
1093
- }
1094
- let s = start;
1095
- let e = end;
1096
- let refNameMatched = false;
1097
- const predicate = (r) => {
1098
- if (refName === r.refName) {
1099
- refNameMatched = true;
1100
- if (s === undefined) {
1101
- s = r.start;
1102
- }
1103
- if (e === undefined) {
1104
- e = r.end;
1105
- }
1106
- if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
1107
- return true;
1108
- }
1109
- s = start;
1110
- e = end;
1111
- }
1112
- return false;
1113
- };
1114
- const lastIndex = findLastIndex(self.displayedRegions, predicate);
1115
- let index;
1116
- while (index !== lastIndex) {
1117
- try {
1118
- const previousIndex = index;
1119
- index = self.displayedRegions
1120
- .slice(previousIndex === undefined ? 0 : previousIndex + 1)
1121
- .findIndex(predicate);
1122
- if (previousIndex !== undefined) {
1123
- index += previousIndex + 1;
1124
- }
1125
- if (!refNameMatched) {
1126
- throw new Error(`could not find a region with refName "${refName}"`);
1127
- }
1128
- if (s === undefined) {
1129
- throw new Error(`could not find a region with refName "${refName}" that contained an end position ${e}`);
1130
- }
1131
- if (e === undefined) {
1132
- throw new Error(`could not find a region with refName "${refName}" that contained a start position ${s + 1}`);
1133
- }
1134
- if (index === -1) {
1135
- throw new Error(`could not find a region that completely contained "${assembleLocString(firstLocation)}"`);
1136
- }
1137
- if (locations.length === 1) {
1138
- const f = self.displayedRegions[index];
1139
- this.moveTo({ index, offset: f.reversed ? f.end - e : s - f.start }, { index, offset: f.reversed ? f.end - s : e - f.start });
1140
- return;
1141
- }
1142
- let locationIndex = 0;
1143
- let locationStart = 0;
1144
- let locationEnd = 0;
1145
- for (locationIndex; locationIndex < locations.length; locationIndex++) {
1146
- const location = locations[locationIndex];
1147
- const region = self.displayedRegions[index + locationIndex];
1148
- locationStart = location.start || region.start;
1149
- locationEnd = location.end || region.end;
1150
- if (location.refName !== region.refName) {
1151
- throw new Error(`Entered location ${assembleLocString(location)} does not match with displayed regions`);
1152
- }
1153
- }
1154
- locationIndex -= 1;
1155
- const startDisplayedRegion = self.displayedRegions[index];
1156
- const endDisplayedRegion = self.displayedRegions[index + locationIndex];
1157
- this.moveTo({
1158
- index,
1159
- offset: startDisplayedRegion.reversed
1160
- ? startDisplayedRegion.end - e
1161
- : s - startDisplayedRegion.start,
1162
- }, {
1163
- index: index + locationIndex,
1164
- offset: endDisplayedRegion.reversed
1165
- ? endDisplayedRegion.end - locationStart
1166
- : locationEnd - endDisplayedRegion.start,
1167
- });
1168
- return;
1169
- }
1170
- catch (error) {
1171
- if (index === lastIndex) {
1172
- throw error;
1173
- }
1174
- }
1175
- }
1176
- },
1177
- }))
1178
- .views(self => ({
1179
- /**
1180
- * #method
1181
- */
1182
- rubberBandMenuItems() {
1183
- return [
1184
- {
1185
- label: 'Zoom to region',
1186
- icon: ZoomInIcon,
1187
- onClick: () => {
1188
- const { leftOffset, rightOffset } = self;
1189
- self.moveTo(leftOffset, rightOffset);
1190
- },
1191
- },
1192
- {
1193
- label: 'Get sequence',
1194
- icon: MenuOpenIcon,
1195
- onClick: () => self.setGetSequenceDialogOpen(true),
1196
- },
1197
- ];
1198
- },
1199
- /**
1200
- * #method
1201
- */
1202
- bpToPx({ refName, coord, regionNumber, }) {
1203
- return bpToPx({ refName, coord, regionNumber, self });
1204
- },
1205
- /**
1206
- * #method
1207
- * scrolls the view to center on the given bp. if that is not in any
1208
- * of the displayed regions, does nothing
1209
- * @param coord - basepair at which you want to center the view
1210
- * @param refName - refName of the displayedRegion you are centering at
1211
- * @param regionNumber - index of the displayedRegion
1212
- */
1213
- centerAt(coord, refName, regionNumber) {
1214
- const centerPx = this.bpToPx({
1215
- refName,
1216
- coord,
1217
- regionNumber,
1218
- });
1219
- if (centerPx) {
1220
- self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
1221
- }
1222
- },
1223
- /**
1224
- * #method
1225
- */
1226
- pxToBp(px) {
1227
- return pxToBp(self, px);
1228
- },
1229
- /**
1230
- * #getter
1231
- */
1232
- get centerLineInfo() {
1233
- return self.displayedRegions.length
1234
- ? this.pxToBp(self.width / 2)
1235
- : undefined;
1236
- },
1237
- }));
1238
- }
1239
- export { renderToSvg, RefNameAutocomplete, SearchBox, ZoomControls, LinearGenomeView, };
1240
- export { default as ReactComponent } from './components/LinearGenomeView';
10
+ };
11
+ export * from './model';
1241
12
  //# sourceMappingURL=index.js.map