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