@jbrowse/plugin-linear-genome-view 2.1.7 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseLinearDisplay/components/LinearBlocks.d.ts +2 -2
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +2 -22
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
- package/dist/BaseLinearDisplay/components/Tooltip.d.ts +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +149 -4
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +600 -464
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js +19 -1
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +1 -1
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
- package/dist/BasicTrack/configSchema.d.ts +3 -0
- package/dist/BasicTrack/configSchema.js +18 -0
- package/dist/BasicTrack/configSchema.js.map +1 -0
- package/dist/BasicTrack/index.d.ts +3 -0
- package/dist/BasicTrack/index.js +18 -0
- package/dist/BasicTrack/index.js.map +1 -0
- package/dist/FeatureTrack/configSchema.d.ts +3 -0
- package/dist/FeatureTrack/configSchema.js +21 -0
- package/dist/FeatureTrack/configSchema.js.map +1 -0
- package/dist/FeatureTrack/index.d.ts +3 -0
- package/dist/FeatureTrack/index.js +18 -0
- package/dist/FeatureTrack/index.js.map +1 -0
- package/dist/LinearBareDisplay/configSchema.d.ts +5 -1
- package/dist/LinearBareDisplay/configSchema.js +12 -1
- package/dist/LinearBareDisplay/configSchema.js.map +1 -1
- package/dist/LinearBareDisplay/model.d.ts +16 -0
- package/dist/LinearBareDisplay/model.js +16 -0
- package/dist/LinearBareDisplay/model.js.map +1 -1
- package/dist/LinearBasicDisplay/configSchema.d.ts +5 -1
- package/dist/LinearBasicDisplay/configSchema.js +16 -1
- package/dist/LinearBasicDisplay/configSchema.js.map +1 -1
- package/dist/LinearBasicDisplay/model.d.ts +79 -8
- package/dist/LinearBasicDisplay/model.js +167 -111
- package/dist/LinearBasicDisplay/model.js.map +1 -1
- package/dist/LinearGenomeView/components/CenterLine.d.ts +1 -1
- package/dist/LinearGenomeView/components/GetSequenceDialog.d.ts +1 -1
- package/dist/LinearGenomeView/components/Gridlines.d.ts +1 -1
- package/dist/LinearGenomeView/components/Header.d.ts +1 -1
- package/dist/LinearGenomeView/components/ImportForm.d.ts +1 -1
- package/dist/LinearGenomeView/components/ImportForm.js +38 -31
- package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeView.d.ts +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeView.js +2 -24
- package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js +7 -5
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/dist/LinearGenomeView/components/OverviewRubberBand.d.ts +1 -1
- package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +27 -35
- package/dist/LinearGenomeView/components/RubberBand.d.ts +1 -1
- package/dist/LinearGenomeView/components/ScaleBar.d.ts +1 -1
- package/dist/LinearGenomeView/components/TrackContainer.d.ts +1 -1
- package/dist/LinearGenomeView/components/TrackContainer.js +12 -9
- package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/dist/LinearGenomeView/components/TrackLabel.js +9 -1
- package/dist/LinearGenomeView/components/TrackLabel.js.map +1 -1
- package/dist/LinearGenomeView/components/TracksContainer.d.ts +1 -1
- package/dist/LinearGenomeView/index.d.ts +273 -18
- package/dist/LinearGenomeView/index.js +409 -90
- package/dist/LinearGenomeView/index.js.map +1 -1
- package/dist/index.d.ts +30 -90
- package/dist/index.js +4 -25
- package/dist/index.js.map +1 -1
- package/esm/BaseLinearDisplay/components/LinearBlocks.d.ts +2 -2
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +2 -22
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
- package/esm/BaseLinearDisplay/components/Tooltip.d.ts +1 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +149 -4
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +600 -464
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js +19 -1
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +1 -1
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
- package/esm/BasicTrack/configSchema.d.ts +3 -0
- package/esm/BasicTrack/configSchema.js +16 -0
- package/esm/BasicTrack/configSchema.js.map +1 -0
- package/esm/BasicTrack/index.d.ts +3 -0
- package/esm/BasicTrack/index.js +13 -0
- package/esm/BasicTrack/index.js.map +1 -0
- package/esm/FeatureTrack/configSchema.d.ts +3 -0
- package/esm/FeatureTrack/configSchema.js +19 -0
- package/esm/FeatureTrack/configSchema.js.map +1 -0
- package/esm/FeatureTrack/index.d.ts +3 -0
- package/esm/FeatureTrack/index.js +13 -0
- package/esm/FeatureTrack/index.js.map +1 -0
- package/esm/LinearBareDisplay/configSchema.d.ts +5 -1
- package/esm/LinearBareDisplay/configSchema.js +14 -2
- package/esm/LinearBareDisplay/configSchema.js.map +1 -1
- package/esm/LinearBareDisplay/model.d.ts +16 -0
- package/esm/LinearBareDisplay/model.js +16 -0
- package/esm/LinearBareDisplay/model.js.map +1 -1
- package/esm/LinearBasicDisplay/configSchema.d.ts +5 -1
- package/esm/LinearBasicDisplay/configSchema.js +18 -2
- package/esm/LinearBasicDisplay/configSchema.js.map +1 -1
- package/esm/LinearBasicDisplay/model.d.ts +79 -8
- package/esm/LinearBasicDisplay/model.js +167 -111
- package/esm/LinearBasicDisplay/model.js.map +1 -1
- package/esm/LinearGenomeView/components/CenterLine.d.ts +1 -1
- package/esm/LinearGenomeView/components/GetSequenceDialog.d.ts +1 -1
- package/esm/LinearGenomeView/components/Gridlines.d.ts +1 -1
- package/esm/LinearGenomeView/components/Header.d.ts +1 -1
- package/esm/LinearGenomeView/components/ImportForm.d.ts +1 -1
- package/esm/LinearGenomeView/components/ImportForm.js +40 -33
- package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeView.d.ts +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeView.js +3 -25
- package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js +7 -5
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/esm/LinearGenomeView/components/OverviewRubberBand.d.ts +1 -1
- package/esm/LinearGenomeView/components/OverviewScaleBar.d.ts +27 -35
- package/esm/LinearGenomeView/components/RubberBand.d.ts +1 -1
- package/esm/LinearGenomeView/components/ScaleBar.d.ts +1 -1
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +1 -1
- package/esm/LinearGenomeView/components/TrackContainer.js +13 -10
- package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/esm/LinearGenomeView/components/TrackLabel.js +9 -1
- package/esm/LinearGenomeView/components/TrackLabel.js.map +1 -1
- package/esm/LinearGenomeView/components/TracksContainer.d.ts +1 -1
- package/esm/LinearGenomeView/index.d.ts +273 -18
- package/esm/LinearGenomeView/index.js +409 -90
- package/esm/LinearGenomeView/index.js.map +1 -1
- package/esm/index.d.ts +30 -90
- package/esm/index.js +4 -25
- package/esm/index.js.map +1 -1
- package/package.json +2 -2
- package/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx +2 -24
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +695 -555
- package/src/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.ts +20 -1
- package/src/BasicTrack/configSchema.ts +23 -0
- package/src/BasicTrack/index.ts +18 -0
- package/src/FeatureTrack/configSchema.ts +27 -0
- package/src/FeatureTrack/index.ts +21 -0
- package/src/LinearBareDisplay/configSchema.ts +15 -2
- package/src/LinearBareDisplay/model.ts +16 -0
- package/src/LinearBasicDisplay/configSchema.ts +19 -2
- package/src/LinearBasicDisplay/model.ts +63 -11
- package/src/LinearGenomeView/components/ImportForm.tsx +85 -67
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +3 -33
- package/src/LinearGenomeView/components/LinearGenomeViewSvg.tsx +21 -18
- package/src/LinearGenomeView/components/TrackContainer.tsx +38 -27
- package/src/LinearGenomeView/components/TrackLabel.tsx +10 -1
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +204 -204
- package/src/LinearGenomeView/index.test.ts +33 -26
- package/src/LinearGenomeView/index.tsx +471 -133
- package/src/index.ts +6 -46
|
@@ -31,12 +31,13 @@ import MiniControls from './components/MiniControls';
|
|
|
31
31
|
import Header from './components/Header';
|
|
32
32
|
import ZoomControls from './components/ZoomControls';
|
|
33
33
|
import LinearGenomeView from './components/LinearGenomeView';
|
|
34
|
+
// lazies
|
|
34
35
|
const SequenceSearchDialog = lazy(() => import('./components/SequenceSearchDialog'));
|
|
35
36
|
function calculateVisibleLocStrings(contentBlocks) {
|
|
36
37
|
if (!contentBlocks.length) {
|
|
37
38
|
return '';
|
|
38
39
|
}
|
|
39
|
-
const isSingleAssemblyName = contentBlocks.every(
|
|
40
|
+
const isSingleAssemblyName = contentBlocks.every(b => b.assemblyName === contentBlocks[0].assemblyName);
|
|
40
41
|
const locs = contentBlocks.map(block => assembleLocString({
|
|
41
42
|
...block,
|
|
42
43
|
start: Math.round(block.start),
|
|
@@ -57,30 +58,87 @@ function localStorageGetItem(item) {
|
|
|
57
58
|
? localStorage.getItem(item)
|
|
58
59
|
: undefined;
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* #stateModel LinearGenomeView
|
|
63
|
+
*/
|
|
60
64
|
export function stateModelFactory(pluginManager) {
|
|
61
65
|
return types
|
|
62
66
|
.compose(BaseViewModel, types.model('LinearGenomeView', {
|
|
67
|
+
/**
|
|
68
|
+
* #property
|
|
69
|
+
*/
|
|
63
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
|
+
*/
|
|
64
77
|
type: types.literal('LinearGenomeView'),
|
|
78
|
+
/**
|
|
79
|
+
* #property
|
|
80
|
+
* corresponds roughly to the horizontal scroll of the LGV
|
|
81
|
+
*/
|
|
65
82
|
offsetPx: 0,
|
|
83
|
+
/**
|
|
84
|
+
* #property
|
|
85
|
+
* corresponds roughly to the zoom level, base-pairs per pixel
|
|
86
|
+
*/
|
|
66
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
|
+
*/
|
|
67
94
|
displayedRegions: types.array(MUIRegion),
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
/**
|
|
96
|
+
* #property
|
|
97
|
+
* array of currently displayed tracks state models instances
|
|
98
|
+
*/
|
|
70
99
|
tracks: types.array(pluginManager.pluggableMstType('track', 'stateModel')),
|
|
100
|
+
/**
|
|
101
|
+
* #property
|
|
102
|
+
* array of currently displayed tracks state model's
|
|
103
|
+
*/
|
|
71
104
|
hideHeader: false,
|
|
105
|
+
/**
|
|
106
|
+
* #property
|
|
107
|
+
*/
|
|
72
108
|
hideHeaderOverview: false,
|
|
109
|
+
/**
|
|
110
|
+
* #property
|
|
111
|
+
*/
|
|
73
112
|
hideNoTracksActive: false,
|
|
113
|
+
/**
|
|
114
|
+
* #property
|
|
115
|
+
*/
|
|
74
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
|
+
*/
|
|
75
121
|
trackLabels: types.optional(types.string, () => localStorageGetItem('lgv-trackLabels') || 'overlapping'),
|
|
122
|
+
/**
|
|
123
|
+
* #property
|
|
124
|
+
* show the "center line"
|
|
125
|
+
*/
|
|
76
126
|
showCenterLine: types.optional(types.boolean, () => {
|
|
77
127
|
const setting = localStorageGetItem('lgv-showCenterLine');
|
|
78
128
|
return setting !== undefined && setting !== null ? !!+setting : false;
|
|
79
129
|
}),
|
|
130
|
+
/**
|
|
131
|
+
* #property
|
|
132
|
+
* show the "cytobands" in the overview scale bar
|
|
133
|
+
*/
|
|
80
134
|
showCytobandsSetting: types.optional(types.boolean, () => {
|
|
81
135
|
const setting = localStorageGetItem('lgv-showCytobands');
|
|
82
136
|
return setting !== undefined && setting !== null ? !!+setting : true;
|
|
83
137
|
}),
|
|
138
|
+
/**
|
|
139
|
+
* #property
|
|
140
|
+
* show the "gridlines" in the track area
|
|
141
|
+
*/
|
|
84
142
|
showGridlines: true,
|
|
85
143
|
}))
|
|
86
144
|
.volatile(() => ({
|
|
@@ -103,15 +161,24 @@ export function stateModelFactory(pluginManager) {
|
|
|
103
161
|
seqDialogDisplayed: false,
|
|
104
162
|
}))
|
|
105
163
|
.views(self => ({
|
|
164
|
+
/**
|
|
165
|
+
* #getter
|
|
166
|
+
*/
|
|
106
167
|
get width() {
|
|
107
168
|
if (self.volatileWidth === undefined) {
|
|
108
169
|
throw new Error('width undefined, make sure to check for model.initialized');
|
|
109
170
|
}
|
|
110
171
|
return self.volatileWidth;
|
|
111
172
|
},
|
|
173
|
+
/**
|
|
174
|
+
* #getter
|
|
175
|
+
*/
|
|
112
176
|
get interRegionPaddingWidth() {
|
|
113
177
|
return INTER_REGION_PADDING_WIDTH;
|
|
114
178
|
},
|
|
179
|
+
/**
|
|
180
|
+
* #getter
|
|
181
|
+
*/
|
|
115
182
|
get assemblyNames() {
|
|
116
183
|
return [
|
|
117
184
|
...new Set(self.displayedRegions.map(region => region.assemblyName)),
|
|
@@ -119,14 +186,23 @@ export function stateModelFactory(pluginManager) {
|
|
|
119
186
|
},
|
|
120
187
|
}))
|
|
121
188
|
.views(self => ({
|
|
189
|
+
/**
|
|
190
|
+
* #method
|
|
191
|
+
*/
|
|
122
192
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
193
|
MiniControlsComponent() {
|
|
124
194
|
return MiniControls;
|
|
125
195
|
},
|
|
196
|
+
/**
|
|
197
|
+
* #method
|
|
198
|
+
*/
|
|
126
199
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
200
|
HeaderComponent() {
|
|
128
201
|
return Header;
|
|
129
202
|
},
|
|
203
|
+
/**
|
|
204
|
+
* #getter
|
|
205
|
+
*/
|
|
130
206
|
get assemblyErrors() {
|
|
131
207
|
const { assemblyManager } = getSession(self);
|
|
132
208
|
const { assemblyNames } = self;
|
|
@@ -135,23 +211,41 @@ export function stateModelFactory(pluginManager) {
|
|
|
135
211
|
.filter(f => !!f)
|
|
136
212
|
.join(', ');
|
|
137
213
|
},
|
|
214
|
+
/**
|
|
215
|
+
* #getter
|
|
216
|
+
*/
|
|
138
217
|
get assembliesInitialized() {
|
|
139
218
|
const { assemblyManager } = getSession(self);
|
|
140
219
|
const { assemblyNames } = self;
|
|
141
220
|
return assemblyNames.every(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.initialized; });
|
|
142
221
|
},
|
|
222
|
+
/**
|
|
223
|
+
* #getter
|
|
224
|
+
*/
|
|
143
225
|
get initialized() {
|
|
144
226
|
return self.volatileWidth !== undefined && this.assembliesInitialized;
|
|
145
227
|
},
|
|
228
|
+
/**
|
|
229
|
+
* #getter
|
|
230
|
+
*/
|
|
146
231
|
get hasDisplayedRegions() {
|
|
147
232
|
return self.displayedRegions.length > 0;
|
|
148
233
|
},
|
|
234
|
+
/**
|
|
235
|
+
* #getter
|
|
236
|
+
*/
|
|
149
237
|
get isSearchDialogDisplayed() {
|
|
150
238
|
return self.searchResults !== undefined;
|
|
151
239
|
},
|
|
240
|
+
/**
|
|
241
|
+
* #getter
|
|
242
|
+
*/
|
|
152
243
|
get scaleBarHeight() {
|
|
153
244
|
return SCALE_BAR_HEIGHT + RESIZE_HANDLE_HEIGHT;
|
|
154
245
|
},
|
|
246
|
+
/**
|
|
247
|
+
* #getter
|
|
248
|
+
*/
|
|
155
249
|
get headerHeight() {
|
|
156
250
|
if (self.hideHeader) {
|
|
157
251
|
return 0;
|
|
@@ -161,44 +255,77 @@ export function stateModelFactory(pluginManager) {
|
|
|
161
255
|
}
|
|
162
256
|
return HEADER_BAR_HEIGHT + HEADER_OVERVIEW_HEIGHT;
|
|
163
257
|
},
|
|
258
|
+
/**
|
|
259
|
+
* #getter
|
|
260
|
+
*/
|
|
164
261
|
get trackHeights() {
|
|
165
262
|
return self.tracks
|
|
166
263
|
.map(t => t.displays[0].height)
|
|
167
264
|
.reduce((a, b) => a + b, 0);
|
|
168
265
|
},
|
|
266
|
+
/**
|
|
267
|
+
* #getter
|
|
268
|
+
*/
|
|
169
269
|
get trackHeightsWithResizeHandles() {
|
|
170
270
|
return this.trackHeights + self.tracks.length * RESIZE_HANDLE_HEIGHT;
|
|
171
271
|
},
|
|
272
|
+
/**
|
|
273
|
+
* #getter
|
|
274
|
+
*/
|
|
172
275
|
get height() {
|
|
173
276
|
return (this.trackHeightsWithResizeHandles +
|
|
174
277
|
this.headerHeight +
|
|
175
278
|
this.scaleBarHeight);
|
|
176
279
|
},
|
|
280
|
+
/**
|
|
281
|
+
* #getter
|
|
282
|
+
*/
|
|
177
283
|
get totalBp() {
|
|
178
284
|
return self.displayedRegions.reduce((a, b) => a + b.end - b.start, 0);
|
|
179
285
|
},
|
|
286
|
+
/**
|
|
287
|
+
* #getter
|
|
288
|
+
*/
|
|
180
289
|
get maxBpPerPx() {
|
|
181
290
|
return this.totalBp / (self.width * 0.9);
|
|
182
291
|
},
|
|
292
|
+
/**
|
|
293
|
+
* #getter
|
|
294
|
+
*/
|
|
183
295
|
get minBpPerPx() {
|
|
184
296
|
return 1 / 50;
|
|
185
297
|
},
|
|
298
|
+
/**
|
|
299
|
+
* #getter
|
|
300
|
+
*/
|
|
186
301
|
get error() {
|
|
187
302
|
return self.volatileError || this.assemblyErrors;
|
|
188
303
|
},
|
|
304
|
+
/**
|
|
305
|
+
* #getter
|
|
306
|
+
*/
|
|
189
307
|
get maxOffset() {
|
|
190
308
|
// objectively determined to keep the linear genome on the main screen
|
|
191
309
|
const leftPadding = 10;
|
|
192
310
|
return this.displayedRegionsTotalPx - leftPadding;
|
|
193
311
|
},
|
|
312
|
+
/**
|
|
313
|
+
* #getter
|
|
314
|
+
*/
|
|
194
315
|
get minOffset() {
|
|
195
316
|
// objectively determined to keep the linear genome on the main screen
|
|
196
317
|
const rightPadding = 30;
|
|
197
318
|
return -self.width + rightPadding;
|
|
198
319
|
},
|
|
320
|
+
/**
|
|
321
|
+
* #getter
|
|
322
|
+
*/
|
|
199
323
|
get displayedRegionsTotalPx() {
|
|
200
324
|
return this.totalBp / self.bpPerPx;
|
|
201
325
|
},
|
|
326
|
+
/**
|
|
327
|
+
* #method
|
|
328
|
+
*/
|
|
202
329
|
renderProps() {
|
|
203
330
|
return {
|
|
204
331
|
...getParentRenderProps(self),
|
|
@@ -206,6 +333,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
206
333
|
highResolutionScaling: getConf(getSession(self), 'highResolutionScaling'),
|
|
207
334
|
};
|
|
208
335
|
},
|
|
336
|
+
/**
|
|
337
|
+
* #method
|
|
338
|
+
*/
|
|
209
339
|
searchScope(assemblyName) {
|
|
210
340
|
return {
|
|
211
341
|
assemblyName,
|
|
@@ -213,9 +343,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
213
343
|
tracks: self.tracks,
|
|
214
344
|
};
|
|
215
345
|
},
|
|
346
|
+
/**
|
|
347
|
+
* #method
|
|
348
|
+
*/
|
|
216
349
|
getTrack(id) {
|
|
217
350
|
return self.tracks.find(t => t.configuration.trackId === id);
|
|
218
351
|
},
|
|
352
|
+
/**
|
|
353
|
+
* #method
|
|
354
|
+
*/
|
|
219
355
|
rankSearchResults(results) {
|
|
220
356
|
// order of rank
|
|
221
357
|
const openTrackIds = self.tracks.map(track => track.configuration.trackId);
|
|
@@ -226,7 +362,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
226
362
|
});
|
|
227
363
|
return results;
|
|
228
364
|
},
|
|
229
|
-
|
|
365
|
+
/**
|
|
366
|
+
* #method
|
|
367
|
+
* modifies view menu action onClick to apply to all tracks of same type
|
|
368
|
+
*/
|
|
230
369
|
rewriteOnClicks(trackType, viewMenuActions) {
|
|
231
370
|
viewMenuActions.forEach(action => {
|
|
232
371
|
// go to lowest level menu
|
|
@@ -245,6 +384,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
245
384
|
}
|
|
246
385
|
});
|
|
247
386
|
},
|
|
387
|
+
/**
|
|
388
|
+
* #getter
|
|
389
|
+
*/
|
|
248
390
|
get trackTypeActions() {
|
|
249
391
|
const allActions = new Map();
|
|
250
392
|
self.tracks.forEach(track => {
|
|
@@ -259,33 +401,60 @@ export function stateModelFactory(pluginManager) {
|
|
|
259
401
|
},
|
|
260
402
|
}))
|
|
261
403
|
.actions(self => ({
|
|
404
|
+
/**
|
|
405
|
+
* #action
|
|
406
|
+
*/
|
|
262
407
|
setShowCytobands(flag) {
|
|
263
408
|
self.showCytobandsSetting = flag;
|
|
264
409
|
localStorage.setItem('lgv-showCytobands', `${+flag}`);
|
|
265
410
|
},
|
|
411
|
+
/**
|
|
412
|
+
* #action
|
|
413
|
+
*/
|
|
266
414
|
setWidth(newWidth) {
|
|
267
415
|
self.volatileWidth = newWidth;
|
|
268
416
|
},
|
|
417
|
+
/**
|
|
418
|
+
* #action
|
|
419
|
+
*/
|
|
269
420
|
setError(error) {
|
|
270
421
|
self.volatileError = error;
|
|
271
422
|
},
|
|
423
|
+
/**
|
|
424
|
+
* #action
|
|
425
|
+
*/
|
|
272
426
|
toggleHeader() {
|
|
273
427
|
self.hideHeader = !self.hideHeader;
|
|
274
428
|
},
|
|
429
|
+
/**
|
|
430
|
+
* #action
|
|
431
|
+
*/
|
|
275
432
|
toggleHeaderOverview() {
|
|
276
433
|
self.hideHeaderOverview = !self.hideHeaderOverview;
|
|
277
434
|
},
|
|
435
|
+
/**
|
|
436
|
+
* #action
|
|
437
|
+
*/
|
|
278
438
|
toggleNoTracksActive() {
|
|
279
439
|
self.hideNoTracksActive = !self.hideNoTracksActive;
|
|
280
440
|
},
|
|
441
|
+
/**
|
|
442
|
+
* #action
|
|
443
|
+
*/
|
|
281
444
|
toggleShowGridlines() {
|
|
282
445
|
self.showGridlines = !self.showGridlines;
|
|
283
446
|
},
|
|
447
|
+
/**
|
|
448
|
+
* #action
|
|
449
|
+
*/
|
|
284
450
|
scrollTo(offsetPx) {
|
|
285
451
|
const newOffsetPx = clamp(offsetPx, self.minOffset, self.maxOffset);
|
|
286
452
|
self.offsetPx = newOffsetPx;
|
|
287
453
|
return newOffsetPx;
|
|
288
454
|
},
|
|
455
|
+
/**
|
|
456
|
+
* #action
|
|
457
|
+
*/
|
|
289
458
|
zoomTo(bpPerPx) {
|
|
290
459
|
const newBpPerPx = clamp(bpPerPx, self.minBpPerPx, self.maxBpPerPx);
|
|
291
460
|
if (newBpPerPx === self.bpPerPx) {
|
|
@@ -303,22 +472,37 @@ export function stateModelFactory(pluginManager) {
|
|
|
303
472
|
viewWidth / 2));
|
|
304
473
|
return newBpPerPx;
|
|
305
474
|
},
|
|
475
|
+
/**
|
|
476
|
+
* #action
|
|
477
|
+
* sets offsets used in the get sequence dialog
|
|
478
|
+
*/
|
|
306
479
|
setOffsets(left, right) {
|
|
307
|
-
// sets offsets used in the get sequence dialog
|
|
308
480
|
self.leftOffset = left;
|
|
309
481
|
self.rightOffset = right;
|
|
310
482
|
},
|
|
483
|
+
/**
|
|
484
|
+
* #action
|
|
485
|
+
*/
|
|
311
486
|
setSearchResults(results, query) {
|
|
312
487
|
self.searchResults = results;
|
|
313
488
|
self.searchQuery = query;
|
|
314
489
|
},
|
|
490
|
+
/**
|
|
491
|
+
* #action
|
|
492
|
+
*/
|
|
315
493
|
setGetSequenceDialogOpen(open) {
|
|
316
494
|
self.seqDialogDisplayed = open;
|
|
317
495
|
},
|
|
496
|
+
/**
|
|
497
|
+
* #action
|
|
498
|
+
*/
|
|
318
499
|
setNewView(bpPerPx, offsetPx) {
|
|
319
500
|
this.zoomTo(bpPerPx);
|
|
320
501
|
this.scrollTo(offsetPx);
|
|
321
502
|
},
|
|
503
|
+
/**
|
|
504
|
+
* #action
|
|
505
|
+
*/
|
|
322
506
|
horizontallyFlip() {
|
|
323
507
|
self.displayedRegions = cast(self.displayedRegions
|
|
324
508
|
.slice()
|
|
@@ -326,6 +510,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
326
510
|
.map(region => ({ ...region, reversed: !region.reversed })));
|
|
327
511
|
this.scrollTo(self.totalBp / self.bpPerPx - self.offsetPx - self.width);
|
|
328
512
|
},
|
|
513
|
+
/**
|
|
514
|
+
* #action
|
|
515
|
+
*/
|
|
329
516
|
showTrack(trackId, initialSnapshot = {}, displayInitialSnapshot = {}) {
|
|
330
517
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
331
518
|
const conf = resolveIdentifier(schema, getRoot(self), trackId);
|
|
@@ -361,6 +548,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
361
548
|
}
|
|
362
549
|
return t[0];
|
|
363
550
|
},
|
|
551
|
+
/**
|
|
552
|
+
* #action
|
|
553
|
+
*/
|
|
364
554
|
hideTrack(trackId) {
|
|
365
555
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
366
556
|
const conf = resolveIdentifier(schema, getRoot(self), trackId);
|
|
@@ -370,6 +560,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
370
560
|
},
|
|
371
561
|
}))
|
|
372
562
|
.actions(self => ({
|
|
563
|
+
/**
|
|
564
|
+
* #action
|
|
565
|
+
*/
|
|
373
566
|
moveTrack(movingId, targetId) {
|
|
374
567
|
const oldIndex = self.tracks.findIndex(track => track.id === movingId);
|
|
375
568
|
if (oldIndex === -1) {
|
|
@@ -383,6 +576,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
383
576
|
self.tracks.splice(oldIndex, 1);
|
|
384
577
|
self.tracks.splice(newIndex, 0, track);
|
|
385
578
|
},
|
|
579
|
+
/**
|
|
580
|
+
* #action
|
|
581
|
+
*/
|
|
386
582
|
closeView() {
|
|
387
583
|
const parent = getContainingView(self);
|
|
388
584
|
if (parent) {
|
|
@@ -396,6 +592,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
396
592
|
getSession(self).removeView(self);
|
|
397
593
|
}
|
|
398
594
|
},
|
|
595
|
+
/**
|
|
596
|
+
* #action
|
|
597
|
+
*/
|
|
399
598
|
toggleTrack(trackId) {
|
|
400
599
|
// if we have any tracks with that configuration, turn them off
|
|
401
600
|
const hiddenCount = self.hideTrack(trackId);
|
|
@@ -404,18 +603,30 @@ export function stateModelFactory(pluginManager) {
|
|
|
404
603
|
self.showTrack(trackId);
|
|
405
604
|
}
|
|
406
605
|
},
|
|
606
|
+
/**
|
|
607
|
+
* #action
|
|
608
|
+
*/
|
|
407
609
|
setTrackLabels(setting) {
|
|
408
610
|
self.trackLabels = setting;
|
|
409
611
|
localStorage.setItem('lgv-trackLabels', setting);
|
|
410
612
|
},
|
|
613
|
+
/**
|
|
614
|
+
* #action
|
|
615
|
+
*/
|
|
411
616
|
toggleCenterLine() {
|
|
412
617
|
self.showCenterLine = !self.showCenterLine;
|
|
413
618
|
localStorage.setItem('lgv-showCenterLine', `${+self.showCenterLine}`);
|
|
414
619
|
},
|
|
620
|
+
/**
|
|
621
|
+
* #action
|
|
622
|
+
*/
|
|
415
623
|
setDisplayedRegions(regions) {
|
|
416
624
|
self.displayedRegions = cast(regions);
|
|
417
625
|
self.zoomTo(self.bpPerPx);
|
|
418
626
|
},
|
|
627
|
+
/**
|
|
628
|
+
* #action
|
|
629
|
+
*/
|
|
419
630
|
activateTrackSelector() {
|
|
420
631
|
if (self.trackSelectorType === 'hierarchical') {
|
|
421
632
|
const session = getSession(self);
|
|
@@ -428,6 +639,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
428
639
|
throw new Error(`invalid track selector type ${self.trackSelectorType}`);
|
|
429
640
|
},
|
|
430
641
|
/**
|
|
642
|
+
* #method
|
|
431
643
|
* Helper method for the fetchSequence.
|
|
432
644
|
* Retrieves the corresponding regions that were selected by the rubberband
|
|
433
645
|
*
|
|
@@ -449,38 +661,51 @@ export function stateModelFactory(pluginManager) {
|
|
|
449
661
|
end: Math.ceil(region.end),
|
|
450
662
|
}));
|
|
451
663
|
},
|
|
452
|
-
|
|
664
|
+
/**
|
|
665
|
+
* #action
|
|
666
|
+
* schedule something to be run after the next time displayedRegions is set
|
|
667
|
+
*/
|
|
453
668
|
afterDisplayedRegionsSet(cb) {
|
|
454
669
|
self.afterDisplayedRegionsSetCallbacks.push(cb);
|
|
455
670
|
},
|
|
671
|
+
/**
|
|
672
|
+
* #action
|
|
673
|
+
*/
|
|
456
674
|
horizontalScroll(distance) {
|
|
457
675
|
const oldOffsetPx = self.offsetPx;
|
|
458
676
|
// newOffsetPx is the actual offset after the scroll is clamped
|
|
459
677
|
const newOffsetPx = self.scrollTo(self.offsetPx + distance);
|
|
460
678
|
return newOffsetPx - oldOffsetPx;
|
|
461
679
|
},
|
|
680
|
+
/**
|
|
681
|
+
* #action
|
|
682
|
+
*/
|
|
462
683
|
center() {
|
|
463
684
|
const centerBp = self.totalBp / 2;
|
|
464
685
|
const centerPx = centerBp / self.bpPerPx;
|
|
465
686
|
self.scrollTo(Math.round(centerPx - self.width / 2));
|
|
466
687
|
},
|
|
688
|
+
/**
|
|
689
|
+
* #action
|
|
690
|
+
*/
|
|
467
691
|
showAllRegions() {
|
|
468
692
|
self.zoomTo(self.maxBpPerPx);
|
|
469
693
|
this.center();
|
|
470
694
|
},
|
|
695
|
+
/**
|
|
696
|
+
* #action
|
|
697
|
+
*/
|
|
471
698
|
showAllRegionsInAssembly(assemblyName) {
|
|
472
699
|
const session = getSession(self);
|
|
473
700
|
const { assemblyManager } = session;
|
|
474
701
|
if (!assemblyName) {
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (assemblyNames.length > 1) {
|
|
479
|
-
session.notify(`Can't perform this with multiple assemblies currently`);
|
|
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`);
|
|
480
705
|
return;
|
|
481
706
|
}
|
|
482
707
|
;
|
|
483
|
-
[assemblyName] =
|
|
708
|
+
[assemblyName] = [...names];
|
|
484
709
|
}
|
|
485
710
|
const assembly = assemblyManager.get(assemblyName);
|
|
486
711
|
if (assembly) {
|
|
@@ -492,15 +717,24 @@ export function stateModelFactory(pluginManager) {
|
|
|
492
717
|
}
|
|
493
718
|
}
|
|
494
719
|
},
|
|
720
|
+
/**
|
|
721
|
+
* #action
|
|
722
|
+
*/
|
|
495
723
|
setDraggingTrackId(idx) {
|
|
496
724
|
self.draggingTrackId = idx;
|
|
497
725
|
},
|
|
726
|
+
/**
|
|
727
|
+
* #action
|
|
728
|
+
*/
|
|
498
729
|
setScaleFactor(factor) {
|
|
499
730
|
self.scaleFactor = factor;
|
|
500
731
|
},
|
|
501
|
-
|
|
732
|
+
/**
|
|
733
|
+
* #action
|
|
734
|
+
* this "clears the view" and makes the view return to the import form
|
|
735
|
+
*/
|
|
502
736
|
clearView() {
|
|
503
|
-
|
|
737
|
+
self.displayedRegions.clear();
|
|
504
738
|
self.tracks.clear();
|
|
505
739
|
// it is necessary to run these after setting displayed regions empty
|
|
506
740
|
// or else model.offsetPx gets set to Infinity and breaks
|
|
@@ -508,6 +742,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
508
742
|
self.scrollTo(0);
|
|
509
743
|
self.zoomTo(10);
|
|
510
744
|
},
|
|
745
|
+
/**
|
|
746
|
+
* #action
|
|
747
|
+
* creates an svg export and save using FileSaver
|
|
748
|
+
*/
|
|
511
749
|
async exportSvg(opts = {}) {
|
|
512
750
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
513
751
|
const html = await renderToSvg(self, opts);
|
|
@@ -517,6 +755,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
517
755
|
}))
|
|
518
756
|
.actions(self => {
|
|
519
757
|
let cancelLastAnimation = () => { };
|
|
758
|
+
/**
|
|
759
|
+
* #action
|
|
760
|
+
* perform animated slide
|
|
761
|
+
*/
|
|
520
762
|
function slide(viewWidths) {
|
|
521
763
|
const [animate, cancelAnimation] = springAnimate(self.offsetPx, self.offsetPx + self.width * viewWidths, self.scrollTo);
|
|
522
764
|
cancelLastAnimation();
|
|
@@ -527,6 +769,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
527
769
|
})
|
|
528
770
|
.actions(self => {
|
|
529
771
|
let cancelLastAnimation = () => { };
|
|
772
|
+
/**
|
|
773
|
+
* #action
|
|
774
|
+
* perform animated zoom
|
|
775
|
+
*/
|
|
530
776
|
function zoom(targetBpPerPx) {
|
|
531
777
|
self.zoomTo(self.bpPerPx);
|
|
532
778
|
if (
|
|
@@ -548,17 +794,30 @@ export function stateModelFactory(pluginManager) {
|
|
|
548
794
|
return { zoom };
|
|
549
795
|
})
|
|
550
796
|
.views(self => ({
|
|
797
|
+
/**
|
|
798
|
+
* #getter
|
|
799
|
+
*/
|
|
551
800
|
get canShowCytobands() {
|
|
552
801
|
return self.displayedRegions.length === 1 && this.anyCytobandsExist;
|
|
553
802
|
},
|
|
803
|
+
/**
|
|
804
|
+
* #getter
|
|
805
|
+
*/
|
|
554
806
|
get showCytobands() {
|
|
555
807
|
return this.canShowCytobands && self.showCytobandsSetting;
|
|
556
808
|
},
|
|
809
|
+
/**
|
|
810
|
+
* #getter
|
|
811
|
+
*/
|
|
557
812
|
get anyCytobandsExist() {
|
|
558
813
|
const { assemblyManager } = getSession(self);
|
|
559
|
-
|
|
560
|
-
return assemblyNames.some(asm => { var _a, _b; return (_b = (_a = assemblyManager.get(asm)) === null || _a === void 0 ? void 0 : _a.cytobands) === null || _b === void 0 ? void 0 : _b.length; });
|
|
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; });
|
|
561
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
|
+
*/
|
|
562
821
|
get cytobandOffset() {
|
|
563
822
|
return this.showCytobands
|
|
564
823
|
? measureText(self.displayedRegions[0].refName, 12) + 15
|
|
@@ -566,6 +825,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
566
825
|
},
|
|
567
826
|
}))
|
|
568
827
|
.views(self => ({
|
|
828
|
+
/**
|
|
829
|
+
* #method
|
|
830
|
+
* return the view menu items
|
|
831
|
+
*/
|
|
569
832
|
menuItems() {
|
|
570
833
|
const { canShowCytobands, showCytobands } = self;
|
|
571
834
|
const session = getSession(self);
|
|
@@ -613,59 +876,57 @@ export function stateModelFactory(pluginManager) {
|
|
|
613
876
|
icon: SyncAltIcon,
|
|
614
877
|
onClick: self.horizontallyFlip,
|
|
615
878
|
},
|
|
616
|
-
{ type: 'divider' },
|
|
617
|
-
{
|
|
618
|
-
label: 'Show all regions in assembly',
|
|
619
|
-
icon: VisibilityIcon,
|
|
620
|
-
onClick: self.showAllRegionsInAssembly,
|
|
621
|
-
},
|
|
622
|
-
{
|
|
623
|
-
label: 'Show center line',
|
|
624
|
-
icon: VisibilityIcon,
|
|
625
|
-
type: 'checkbox',
|
|
626
|
-
checked: self.showCenterLine,
|
|
627
|
-
onClick: self.toggleCenterLine,
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
label: 'Show header',
|
|
631
|
-
icon: VisibilityIcon,
|
|
632
|
-
type: 'checkbox',
|
|
633
|
-
checked: !self.hideHeader,
|
|
634
|
-
onClick: self.toggleHeader,
|
|
635
|
-
},
|
|
636
879
|
{
|
|
637
|
-
label: 'Show
|
|
880
|
+
label: 'Show...',
|
|
638
881
|
icon: VisibilityIcon,
|
|
639
|
-
|
|
640
|
-
checked: !self.hideHeaderOverview,
|
|
641
|
-
onClick: self.toggleHeaderOverview,
|
|
642
|
-
disabled: self.hideHeader,
|
|
643
|
-
},
|
|
644
|
-
{
|
|
645
|
-
label: 'Show no tracks active button',
|
|
646
|
-
icon: VisibilityIcon,
|
|
647
|
-
type: 'checkbox',
|
|
648
|
-
checked: !self.hideNoTracksActive,
|
|
649
|
-
onClick: self.toggleNoTracksActive,
|
|
650
|
-
},
|
|
651
|
-
{
|
|
652
|
-
label: 'Show guidelines',
|
|
653
|
-
icon: VisibilityIcon,
|
|
654
|
-
type: 'checkbox',
|
|
655
|
-
checked: self.showGridlines,
|
|
656
|
-
onClick: self.toggleShowGridlines,
|
|
657
|
-
},
|
|
658
|
-
...(canShowCytobands
|
|
659
|
-
? [
|
|
882
|
+
subMenu: [
|
|
660
883
|
{
|
|
661
|
-
label: 'Show
|
|
662
|
-
|
|
884
|
+
label: 'Show all regions in assembly',
|
|
885
|
+
onClick: self.showAllRegionsInAssembly,
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
label: 'Show center line',
|
|
663
889
|
type: 'checkbox',
|
|
664
|
-
checked: self.
|
|
665
|
-
onClick:
|
|
890
|
+
checked: self.showCenterLine,
|
|
891
|
+
onClick: self.toggleCenterLine,
|
|
666
892
|
},
|
|
667
|
-
|
|
668
|
-
|
|
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
|
+
},
|
|
669
930
|
{
|
|
670
931
|
label: 'Track labels',
|
|
671
932
|
icon: LabelIcon,
|
|
@@ -708,6 +969,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
708
969
|
let currentlyCalculatedStaticBlocks;
|
|
709
970
|
let stringifiedCurrentlyCalculatedStaticBlocks = '';
|
|
710
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
|
+
*/
|
|
711
981
|
get staticBlocks() {
|
|
712
982
|
const ret = calculateStaticBlocks(self);
|
|
713
983
|
const sret = JSON.stringify(ret);
|
|
@@ -717,27 +987,48 @@ export function stateModelFactory(pluginManager) {
|
|
|
717
987
|
}
|
|
718
988
|
return currentlyCalculatedStaticBlocks;
|
|
719
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
|
+
*/
|
|
720
997
|
get dynamicBlocks() {
|
|
721
998
|
return calculateDynamicBlocks(self);
|
|
722
999
|
},
|
|
1000
|
+
/**
|
|
1001
|
+
* #getter
|
|
1002
|
+
* rounded dynamic blocks are dynamic blocks without fractions of bp
|
|
1003
|
+
*/
|
|
723
1004
|
get roundedDynamicBlocks() {
|
|
724
|
-
return this.dynamicBlocks.contentBlocks.map(block => {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
};
|
|
730
|
-
});
|
|
1005
|
+
return this.dynamicBlocks.contentBlocks.map(block => ({
|
|
1006
|
+
...block,
|
|
1007
|
+
start: Math.floor(block.start),
|
|
1008
|
+
end: Math.ceil(block.end),
|
|
1009
|
+
}));
|
|
731
1010
|
},
|
|
1011
|
+
/**
|
|
1012
|
+
* #getter
|
|
1013
|
+
* a single "combo-locstring" representing all the regions visible
|
|
1014
|
+
* on the screen
|
|
1015
|
+
*/
|
|
732
1016
|
get visibleLocStrings() {
|
|
733
1017
|
return calculateVisibleLocStrings(this.dynamicBlocks.contentBlocks);
|
|
734
1018
|
},
|
|
1019
|
+
/**
|
|
1020
|
+
* #getter
|
|
1021
|
+
* same as visibleLocStrings, but only updated every 300ms
|
|
1022
|
+
*/
|
|
735
1023
|
get coarseVisibleLocStrings() {
|
|
736
1024
|
return calculateVisibleLocStrings(self.coarseDynamicBlocks);
|
|
737
1025
|
},
|
|
738
1026
|
};
|
|
739
1027
|
})
|
|
740
1028
|
.actions(self => ({
|
|
1029
|
+
/**
|
|
1030
|
+
* #action
|
|
1031
|
+
*/
|
|
741
1032
|
setCoarseDynamicBlocks(blocks) {
|
|
742
1033
|
self.coarseDynamicBlocks = blocks.contentBlocks;
|
|
743
1034
|
self.coarseTotalBp = blocks.totalBp;
|
|
@@ -752,6 +1043,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
752
1043
|
}))
|
|
753
1044
|
.actions(self => ({
|
|
754
1045
|
/**
|
|
1046
|
+
* #action
|
|
755
1047
|
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
756
1048
|
* displayed region in the linear genome view
|
|
757
1049
|
*
|
|
@@ -761,7 +1053,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
761
1053
|
moveTo(start, end) {
|
|
762
1054
|
moveTo(self, start, end);
|
|
763
1055
|
},
|
|
764
|
-
|
|
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) {
|
|
765
1064
|
const { assemblyNames } = self;
|
|
766
1065
|
const { assemblyManager } = getSession(self);
|
|
767
1066
|
const { isValidRefName } = assemblyManager;
|
|
@@ -771,6 +1070,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
771
1070
|
.split(/(\s+)/)
|
|
772
1071
|
.map(f => f.trim())
|
|
773
1072
|
.filter(f => !!f);
|
|
1073
|
+
if (assemblyName) {
|
|
1074
|
+
await assemblyManager.waitForAssembly(assemblyName);
|
|
1075
|
+
}
|
|
774
1076
|
// first try interpreting as a whitespace-separated sequence of
|
|
775
1077
|
// multiple locstrings
|
|
776
1078
|
try {
|
|
@@ -791,9 +1093,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
791
1093
|
throw e;
|
|
792
1094
|
}
|
|
793
1095
|
}
|
|
794
|
-
const locations = parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(region => {
|
|
1096
|
+
const locations = await Promise.all(parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(async (region) => {
|
|
795
1097
|
const asmName = region.assemblyName || assemblyName;
|
|
796
|
-
const asm = assemblyManager.
|
|
1098
|
+
const asm = await assemblyManager.waitForAssembly(asmName);
|
|
797
1099
|
const { refName } = region;
|
|
798
1100
|
if (!asm) {
|
|
799
1101
|
throw new Error(`assembly ${asmName} not found`);
|
|
@@ -806,7 +1108,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
806
1108
|
if (!canonicalRefName) {
|
|
807
1109
|
throw new Error(`Could not find refName ${refName} in ${asm.name}`);
|
|
808
1110
|
}
|
|
809
|
-
const parentRegion = regions.find(
|
|
1111
|
+
const parentRegion = regions.find(r => r.refName === canonicalRefName);
|
|
810
1112
|
if (!parentRegion) {
|
|
811
1113
|
throw new Error(`Could not find refName ${refName} in ${asmName}`);
|
|
812
1114
|
}
|
|
@@ -815,7 +1117,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
815
1117
|
assemblyName: asmName,
|
|
816
1118
|
parentRegion,
|
|
817
1119
|
};
|
|
818
|
-
});
|
|
1120
|
+
}));
|
|
819
1121
|
if (locations.length === 1) {
|
|
820
1122
|
const loc = locations[0];
|
|
821
1123
|
self.setDisplayedRegions([
|
|
@@ -836,6 +1138,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
836
1138
|
}
|
|
837
1139
|
},
|
|
838
1140
|
/**
|
|
1141
|
+
* #action
|
|
839
1142
|
* Navigate to a location based on its refName and optionally start, end,
|
|
840
1143
|
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
841
1144
|
* from same refName. Only navigates to a location if it is entirely
|
|
@@ -844,11 +1147,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
844
1147
|
*
|
|
845
1148
|
* Throws an error if navigation was unsuccessful
|
|
846
1149
|
*
|
|
847
|
-
* @param
|
|
1150
|
+
* @param query - a proposed location to navigate to
|
|
848
1151
|
*/
|
|
849
1152
|
navTo(query) {
|
|
850
1153
|
this.navToMultiple([query]);
|
|
851
1154
|
},
|
|
1155
|
+
/**
|
|
1156
|
+
* #action
|
|
1157
|
+
*/
|
|
852
1158
|
navToMultiple(locations) {
|
|
853
1159
|
const firstLocation = locations[0];
|
|
854
1160
|
let { refName } = firstLocation;
|
|
@@ -913,31 +1219,31 @@ export function stateModelFactory(pluginManager) {
|
|
|
913
1219
|
this.moveTo({ index, offset: f.reversed ? f.end - e : s - f.start }, { index, offset: f.reversed ? f.end - s : e - f.start });
|
|
914
1220
|
return;
|
|
915
1221
|
}
|
|
916
|
-
let
|
|
917
|
-
let
|
|
918
|
-
let
|
|
919
|
-
for (
|
|
920
|
-
const location = locations[
|
|
921
|
-
const region = self.displayedRegions[index +
|
|
922
|
-
|
|
923
|
-
|
|
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;
|
|
924
1230
|
if (location.refName !== region.refName) {
|
|
925
1231
|
throw new Error(`Entered location ${assembleLocString(location)} does not match with displayed regions`);
|
|
926
1232
|
}
|
|
927
1233
|
}
|
|
928
|
-
|
|
1234
|
+
idx -= 1;
|
|
929
1235
|
const startDisplayedRegion = self.displayedRegions[index];
|
|
930
|
-
const endDisplayedRegion = self.displayedRegions[index +
|
|
1236
|
+
const endDisplayedRegion = self.displayedRegions[index + idx];
|
|
931
1237
|
this.moveTo({
|
|
932
1238
|
index,
|
|
933
1239
|
offset: startDisplayedRegion.reversed
|
|
934
1240
|
? startDisplayedRegion.end - e
|
|
935
1241
|
: s - startDisplayedRegion.start,
|
|
936
1242
|
}, {
|
|
937
|
-
index: index +
|
|
1243
|
+
index: index + idx,
|
|
938
1244
|
offset: endDisplayedRegion.reversed
|
|
939
|
-
? endDisplayedRegion.end -
|
|
940
|
-
:
|
|
1245
|
+
? endDisplayedRegion.end - start
|
|
1246
|
+
: end - endDisplayedRegion.start,
|
|
941
1247
|
});
|
|
942
1248
|
return;
|
|
943
1249
|
}
|
|
@@ -950,6 +1256,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
950
1256
|
},
|
|
951
1257
|
}))
|
|
952
1258
|
.views(self => ({
|
|
1259
|
+
/**
|
|
1260
|
+
* #method
|
|
1261
|
+
*/
|
|
953
1262
|
rubberBandMenuItems() {
|
|
954
1263
|
return [
|
|
955
1264
|
{
|
|
@@ -967,10 +1276,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
967
1276
|
},
|
|
968
1277
|
];
|
|
969
1278
|
},
|
|
1279
|
+
/**
|
|
1280
|
+
* #method
|
|
1281
|
+
*/
|
|
970
1282
|
bpToPx({ refName, coord, regionNumber, }) {
|
|
971
1283
|
return bpToPx({ refName, coord, regionNumber, self });
|
|
972
1284
|
},
|
|
973
1285
|
/**
|
|
1286
|
+
* #method
|
|
974
1287
|
* scrolls the view to center on the given bp. if that is not in any
|
|
975
1288
|
* of the displayed regions, does nothing
|
|
976
1289
|
* @param coord - basepair at which you want to center the view
|
|
@@ -987,9 +1300,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
987
1300
|
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
|
|
988
1301
|
}
|
|
989
1302
|
},
|
|
1303
|
+
/**
|
|
1304
|
+
* #method
|
|
1305
|
+
*/
|
|
990
1306
|
pxToBp(px) {
|
|
991
1307
|
return pxToBp(self, px);
|
|
992
1308
|
},
|
|
1309
|
+
/**
|
|
1310
|
+
* #getter
|
|
1311
|
+
*/
|
|
993
1312
|
get centerLineInfo() {
|
|
994
1313
|
return self.displayedRegions.length
|
|
995
1314
|
? this.pxToBp(self.width / 2)
|