@jbrowse/plugin-linear-genome-view 2.1.7 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseLinearDisplay/components/LinearBlocks.d.ts +2 -2
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +2 -22
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +146 -1
- 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/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 +77 -6
- package/dist/LinearBasicDisplay/model.js +167 -111
- package/dist/LinearBasicDisplay/model.js.map +1 -1
- package/dist/LinearGenomeView/components/ImportForm.js +34 -28
- package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeView.js +1 -21
- package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js +7 -5
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +26 -34
- package/dist/LinearGenomeView/index.d.ts +189 -15
- package/dist/LinearGenomeView/index.js +266 -27
- package/dist/LinearGenomeView/index.js.map +1 -1
- package/dist/index.d.ts +12 -84
- 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/models/BaseLinearDisplayModel.d.ts +146 -1
- 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/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 +77 -6
- package/esm/LinearBasicDisplay/model.js +167 -111
- package/esm/LinearBasicDisplay/model.js.map +1 -1
- package/esm/LinearGenomeView/components/ImportForm.js +36 -30
- package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeView.js +2 -22
- package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js +7 -5
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/esm/LinearGenomeView/components/OverviewScaleBar.d.ts +26 -34
- package/esm/LinearGenomeView/index.d.ts +189 -15
- package/esm/LinearGenomeView/index.js +266 -27
- package/esm/LinearGenomeView/index.js.map +1 -1
- package/esm/index.d.ts +12 -84
- 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 +22 -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 +79 -63
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +2 -26
- package/src/LinearGenomeView/components/LinearGenomeViewSvg.tsx +21 -18
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +204 -204
- package/src/LinearGenomeView/index.test.ts +33 -26
- package/src/LinearGenomeView/index.tsx +317 -60
- package/src/index.ts +6 -46
|
@@ -36,7 +36,7 @@ function calculateVisibleLocStrings(contentBlocks) {
|
|
|
36
36
|
if (!contentBlocks.length) {
|
|
37
37
|
return '';
|
|
38
38
|
}
|
|
39
|
-
const isSingleAssemblyName = contentBlocks.every(
|
|
39
|
+
const isSingleAssemblyName = contentBlocks.every(b => b.assemblyName === contentBlocks[0].assemblyName);
|
|
40
40
|
const locs = contentBlocks.map(block => assembleLocString({
|
|
41
41
|
...block,
|
|
42
42
|
start: Math.round(block.start),
|
|
@@ -57,30 +57,84 @@ function localStorageGetItem(item) {
|
|
|
57
57
|
? localStorage.getItem(item)
|
|
58
58
|
: undefined;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* #stateModel LinearGenomeView
|
|
62
|
+
*/
|
|
60
63
|
export function stateModelFactory(pluginManager) {
|
|
61
64
|
return types
|
|
62
65
|
.compose(BaseViewModel, types.model('LinearGenomeView', {
|
|
66
|
+
/**
|
|
67
|
+
* #property
|
|
68
|
+
*/
|
|
63
69
|
id: ElementId,
|
|
70
|
+
/**
|
|
71
|
+
* #property
|
|
72
|
+
*/
|
|
64
73
|
type: types.literal('LinearGenomeView'),
|
|
74
|
+
/**
|
|
75
|
+
* #property
|
|
76
|
+
* corresponds roughly to the horizontal scroll of the LGV
|
|
77
|
+
*/
|
|
65
78
|
offsetPx: 0,
|
|
79
|
+
/**
|
|
80
|
+
* #property
|
|
81
|
+
* corresponds roughly to the zoom level, base-pairs per pixel
|
|
82
|
+
*/
|
|
66
83
|
bpPerPx: 1,
|
|
84
|
+
/**
|
|
85
|
+
* #property
|
|
86
|
+
* currently displayed regions, can be a single chromosome, arbitrary subsections,
|
|
87
|
+
* or the entire set of chromosomes in the genome, but it not advised to use the
|
|
88
|
+
* entire set of chromosomes if your assembly is very fragmented
|
|
89
|
+
*/
|
|
67
90
|
displayedRegions: types.array(MUIRegion),
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
/**
|
|
92
|
+
* #property
|
|
93
|
+
* array of currently displayed tracks state models instances
|
|
94
|
+
*/
|
|
70
95
|
tracks: types.array(pluginManager.pluggableMstType('track', 'stateModel')),
|
|
96
|
+
/**
|
|
97
|
+
* #property
|
|
98
|
+
* array of currently displayed tracks state model's
|
|
99
|
+
*/
|
|
71
100
|
hideHeader: false,
|
|
101
|
+
/**
|
|
102
|
+
* #property
|
|
103
|
+
*/
|
|
72
104
|
hideHeaderOverview: false,
|
|
105
|
+
/**
|
|
106
|
+
* #property
|
|
107
|
+
*/
|
|
73
108
|
hideNoTracksActive: false,
|
|
109
|
+
/**
|
|
110
|
+
* #property
|
|
111
|
+
*/
|
|
74
112
|
trackSelectorType: types.optional(types.enumeration(['hierarchical']), 'hierarchical'),
|
|
113
|
+
/**
|
|
114
|
+
* #property
|
|
115
|
+
* how to display the track labels, can be "overlapping", "offset", or "hidden"
|
|
116
|
+
*/
|
|
75
117
|
trackLabels: types.optional(types.string, () => localStorageGetItem('lgv-trackLabels') || 'overlapping'),
|
|
118
|
+
/**
|
|
119
|
+
* #property
|
|
120
|
+
* show the "center line"
|
|
121
|
+
*/
|
|
76
122
|
showCenterLine: types.optional(types.boolean, () => {
|
|
77
123
|
const setting = localStorageGetItem('lgv-showCenterLine');
|
|
78
124
|
return setting !== undefined && setting !== null ? !!+setting : false;
|
|
79
125
|
}),
|
|
126
|
+
/**
|
|
127
|
+
* #property
|
|
128
|
+
* show the "cytobands" in the overview scale bar
|
|
129
|
+
*/
|
|
80
130
|
showCytobandsSetting: types.optional(types.boolean, () => {
|
|
81
131
|
const setting = localStorageGetItem('lgv-showCytobands');
|
|
82
132
|
return setting !== undefined && setting !== null ? !!+setting : true;
|
|
83
133
|
}),
|
|
134
|
+
/**
|
|
135
|
+
* #property
|
|
136
|
+
* show the "gridlines" in the track area
|
|
137
|
+
*/
|
|
84
138
|
showGridlines: true,
|
|
85
139
|
}))
|
|
86
140
|
.volatile(() => ({
|
|
@@ -103,15 +157,24 @@ export function stateModelFactory(pluginManager) {
|
|
|
103
157
|
seqDialogDisplayed: false,
|
|
104
158
|
}))
|
|
105
159
|
.views(self => ({
|
|
160
|
+
/**
|
|
161
|
+
* #getter
|
|
162
|
+
*/
|
|
106
163
|
get width() {
|
|
107
164
|
if (self.volatileWidth === undefined) {
|
|
108
165
|
throw new Error('width undefined, make sure to check for model.initialized');
|
|
109
166
|
}
|
|
110
167
|
return self.volatileWidth;
|
|
111
168
|
},
|
|
169
|
+
/**
|
|
170
|
+
* #getter
|
|
171
|
+
*/
|
|
112
172
|
get interRegionPaddingWidth() {
|
|
113
173
|
return INTER_REGION_PADDING_WIDTH;
|
|
114
174
|
},
|
|
175
|
+
/**
|
|
176
|
+
* #getter
|
|
177
|
+
*/
|
|
115
178
|
get assemblyNames() {
|
|
116
179
|
return [
|
|
117
180
|
...new Set(self.displayedRegions.map(region => region.assemblyName)),
|
|
@@ -259,33 +322,60 @@ export function stateModelFactory(pluginManager) {
|
|
|
259
322
|
},
|
|
260
323
|
}))
|
|
261
324
|
.actions(self => ({
|
|
325
|
+
/**
|
|
326
|
+
* #action
|
|
327
|
+
*/
|
|
262
328
|
setShowCytobands(flag) {
|
|
263
329
|
self.showCytobandsSetting = flag;
|
|
264
330
|
localStorage.setItem('lgv-showCytobands', `${+flag}`);
|
|
265
331
|
},
|
|
332
|
+
/**
|
|
333
|
+
* #action
|
|
334
|
+
*/
|
|
266
335
|
setWidth(newWidth) {
|
|
267
336
|
self.volatileWidth = newWidth;
|
|
268
337
|
},
|
|
338
|
+
/**
|
|
339
|
+
* #action
|
|
340
|
+
*/
|
|
269
341
|
setError(error) {
|
|
270
342
|
self.volatileError = error;
|
|
271
343
|
},
|
|
344
|
+
/**
|
|
345
|
+
* #action
|
|
346
|
+
*/
|
|
272
347
|
toggleHeader() {
|
|
273
348
|
self.hideHeader = !self.hideHeader;
|
|
274
349
|
},
|
|
350
|
+
/**
|
|
351
|
+
* #action
|
|
352
|
+
*/
|
|
275
353
|
toggleHeaderOverview() {
|
|
276
354
|
self.hideHeaderOverview = !self.hideHeaderOverview;
|
|
277
355
|
},
|
|
356
|
+
/**
|
|
357
|
+
* #action
|
|
358
|
+
*/
|
|
278
359
|
toggleNoTracksActive() {
|
|
279
360
|
self.hideNoTracksActive = !self.hideNoTracksActive;
|
|
280
361
|
},
|
|
362
|
+
/**
|
|
363
|
+
* #action
|
|
364
|
+
*/
|
|
281
365
|
toggleShowGridlines() {
|
|
282
366
|
self.showGridlines = !self.showGridlines;
|
|
283
367
|
},
|
|
368
|
+
/**
|
|
369
|
+
* #action
|
|
370
|
+
*/
|
|
284
371
|
scrollTo(offsetPx) {
|
|
285
372
|
const newOffsetPx = clamp(offsetPx, self.minOffset, self.maxOffset);
|
|
286
373
|
self.offsetPx = newOffsetPx;
|
|
287
374
|
return newOffsetPx;
|
|
288
375
|
},
|
|
376
|
+
/**
|
|
377
|
+
* #action
|
|
378
|
+
*/
|
|
289
379
|
zoomTo(bpPerPx) {
|
|
290
380
|
const newBpPerPx = clamp(bpPerPx, self.minBpPerPx, self.maxBpPerPx);
|
|
291
381
|
if (newBpPerPx === self.bpPerPx) {
|
|
@@ -303,22 +393,37 @@ export function stateModelFactory(pluginManager) {
|
|
|
303
393
|
viewWidth / 2));
|
|
304
394
|
return newBpPerPx;
|
|
305
395
|
},
|
|
396
|
+
/**
|
|
397
|
+
* #action
|
|
398
|
+
* sets offsets used in the get sequence dialog
|
|
399
|
+
*/
|
|
306
400
|
setOffsets(left, right) {
|
|
307
|
-
// sets offsets used in the get sequence dialog
|
|
308
401
|
self.leftOffset = left;
|
|
309
402
|
self.rightOffset = right;
|
|
310
403
|
},
|
|
404
|
+
/**
|
|
405
|
+
* #action
|
|
406
|
+
*/
|
|
311
407
|
setSearchResults(results, query) {
|
|
312
408
|
self.searchResults = results;
|
|
313
409
|
self.searchQuery = query;
|
|
314
410
|
},
|
|
411
|
+
/**
|
|
412
|
+
* #action
|
|
413
|
+
*/
|
|
315
414
|
setGetSequenceDialogOpen(open) {
|
|
316
415
|
self.seqDialogDisplayed = open;
|
|
317
416
|
},
|
|
417
|
+
/**
|
|
418
|
+
* #action
|
|
419
|
+
*/
|
|
318
420
|
setNewView(bpPerPx, offsetPx) {
|
|
319
421
|
this.zoomTo(bpPerPx);
|
|
320
422
|
this.scrollTo(offsetPx);
|
|
321
423
|
},
|
|
424
|
+
/**
|
|
425
|
+
* #action
|
|
426
|
+
*/
|
|
322
427
|
horizontallyFlip() {
|
|
323
428
|
self.displayedRegions = cast(self.displayedRegions
|
|
324
429
|
.slice()
|
|
@@ -326,6 +431,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
326
431
|
.map(region => ({ ...region, reversed: !region.reversed })));
|
|
327
432
|
this.scrollTo(self.totalBp / self.bpPerPx - self.offsetPx - self.width);
|
|
328
433
|
},
|
|
434
|
+
/**
|
|
435
|
+
* #action
|
|
436
|
+
*/
|
|
329
437
|
showTrack(trackId, initialSnapshot = {}, displayInitialSnapshot = {}) {
|
|
330
438
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
331
439
|
const conf = resolveIdentifier(schema, getRoot(self), trackId);
|
|
@@ -370,6 +478,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
370
478
|
},
|
|
371
479
|
}))
|
|
372
480
|
.actions(self => ({
|
|
481
|
+
/**
|
|
482
|
+
* #action
|
|
483
|
+
*/
|
|
373
484
|
moveTrack(movingId, targetId) {
|
|
374
485
|
const oldIndex = self.tracks.findIndex(track => track.id === movingId);
|
|
375
486
|
if (oldIndex === -1) {
|
|
@@ -383,6 +494,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
383
494
|
self.tracks.splice(oldIndex, 1);
|
|
384
495
|
self.tracks.splice(newIndex, 0, track);
|
|
385
496
|
},
|
|
497
|
+
/**
|
|
498
|
+
* #action
|
|
499
|
+
*/
|
|
386
500
|
closeView() {
|
|
387
501
|
const parent = getContainingView(self);
|
|
388
502
|
if (parent) {
|
|
@@ -396,6 +510,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
396
510
|
getSession(self).removeView(self);
|
|
397
511
|
}
|
|
398
512
|
},
|
|
513
|
+
/**
|
|
514
|
+
* #action
|
|
515
|
+
*/
|
|
399
516
|
toggleTrack(trackId) {
|
|
400
517
|
// if we have any tracks with that configuration, turn them off
|
|
401
518
|
const hiddenCount = self.hideTrack(trackId);
|
|
@@ -404,18 +521,30 @@ export function stateModelFactory(pluginManager) {
|
|
|
404
521
|
self.showTrack(trackId);
|
|
405
522
|
}
|
|
406
523
|
},
|
|
524
|
+
/**
|
|
525
|
+
* #action
|
|
526
|
+
*/
|
|
407
527
|
setTrackLabels(setting) {
|
|
408
528
|
self.trackLabels = setting;
|
|
409
529
|
localStorage.setItem('lgv-trackLabels', setting);
|
|
410
530
|
},
|
|
531
|
+
/**
|
|
532
|
+
* #action
|
|
533
|
+
*/
|
|
411
534
|
toggleCenterLine() {
|
|
412
535
|
self.showCenterLine = !self.showCenterLine;
|
|
413
536
|
localStorage.setItem('lgv-showCenterLine', `${+self.showCenterLine}`);
|
|
414
537
|
},
|
|
538
|
+
/**
|
|
539
|
+
* #action
|
|
540
|
+
*/
|
|
415
541
|
setDisplayedRegions(regions) {
|
|
416
542
|
self.displayedRegions = cast(regions);
|
|
417
543
|
self.zoomTo(self.bpPerPx);
|
|
418
544
|
},
|
|
545
|
+
/**
|
|
546
|
+
* #action
|
|
547
|
+
*/
|
|
419
548
|
activateTrackSelector() {
|
|
420
549
|
if (self.trackSelectorType === 'hierarchical') {
|
|
421
550
|
const session = getSession(self);
|
|
@@ -428,6 +557,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
428
557
|
throw new Error(`invalid track selector type ${self.trackSelectorType}`);
|
|
429
558
|
},
|
|
430
559
|
/**
|
|
560
|
+
* #method
|
|
431
561
|
* Helper method for the fetchSequence.
|
|
432
562
|
* Retrieves the corresponding regions that were selected by the rubberband
|
|
433
563
|
*
|
|
@@ -449,38 +579,51 @@ export function stateModelFactory(pluginManager) {
|
|
|
449
579
|
end: Math.ceil(region.end),
|
|
450
580
|
}));
|
|
451
581
|
},
|
|
452
|
-
|
|
582
|
+
/**
|
|
583
|
+
* #action
|
|
584
|
+
* schedule something to be run after the next time displayedRegions is set
|
|
585
|
+
*/
|
|
453
586
|
afterDisplayedRegionsSet(cb) {
|
|
454
587
|
self.afterDisplayedRegionsSetCallbacks.push(cb);
|
|
455
588
|
},
|
|
589
|
+
/**
|
|
590
|
+
* #action
|
|
591
|
+
*/
|
|
456
592
|
horizontalScroll(distance) {
|
|
457
593
|
const oldOffsetPx = self.offsetPx;
|
|
458
594
|
// newOffsetPx is the actual offset after the scroll is clamped
|
|
459
595
|
const newOffsetPx = self.scrollTo(self.offsetPx + distance);
|
|
460
596
|
return newOffsetPx - oldOffsetPx;
|
|
461
597
|
},
|
|
598
|
+
/**
|
|
599
|
+
* #action
|
|
600
|
+
*/
|
|
462
601
|
center() {
|
|
463
602
|
const centerBp = self.totalBp / 2;
|
|
464
603
|
const centerPx = centerBp / self.bpPerPx;
|
|
465
604
|
self.scrollTo(Math.round(centerPx - self.width / 2));
|
|
466
605
|
},
|
|
606
|
+
/**
|
|
607
|
+
* #action
|
|
608
|
+
*/
|
|
467
609
|
showAllRegions() {
|
|
468
610
|
self.zoomTo(self.maxBpPerPx);
|
|
469
611
|
this.center();
|
|
470
612
|
},
|
|
613
|
+
/**
|
|
614
|
+
* #action
|
|
615
|
+
*/
|
|
471
616
|
showAllRegionsInAssembly(assemblyName) {
|
|
472
617
|
const session = getSession(self);
|
|
473
618
|
const { assemblyManager } = session;
|
|
474
619
|
if (!assemblyName) {
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (assemblyNames.length > 1) {
|
|
479
|
-
session.notify(`Can't perform this with multiple assemblies currently`);
|
|
620
|
+
const names = new Set(self.displayedRegions.map(r => r.assemblyName));
|
|
621
|
+
if (names.size > 1) {
|
|
622
|
+
session.notify(`Can't perform operation with multiple assemblies currently`);
|
|
480
623
|
return;
|
|
481
624
|
}
|
|
482
625
|
;
|
|
483
|
-
[assemblyName] =
|
|
626
|
+
[assemblyName] = [...names];
|
|
484
627
|
}
|
|
485
628
|
const assembly = assemblyManager.get(assemblyName);
|
|
486
629
|
if (assembly) {
|
|
@@ -492,13 +635,22 @@ export function stateModelFactory(pluginManager) {
|
|
|
492
635
|
}
|
|
493
636
|
}
|
|
494
637
|
},
|
|
638
|
+
/**
|
|
639
|
+
* #action
|
|
640
|
+
*/
|
|
495
641
|
setDraggingTrackId(idx) {
|
|
496
642
|
self.draggingTrackId = idx;
|
|
497
643
|
},
|
|
644
|
+
/**
|
|
645
|
+
* #action
|
|
646
|
+
*/
|
|
498
647
|
setScaleFactor(factor) {
|
|
499
648
|
self.scaleFactor = factor;
|
|
500
649
|
},
|
|
501
|
-
|
|
650
|
+
/**
|
|
651
|
+
* #action
|
|
652
|
+
* this "clears the view" and makes the view return to the import form
|
|
653
|
+
*/
|
|
502
654
|
clearView() {
|
|
503
655
|
this.setDisplayedRegions([]);
|
|
504
656
|
self.tracks.clear();
|
|
@@ -508,6 +660,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
508
660
|
self.scrollTo(0);
|
|
509
661
|
self.zoomTo(10);
|
|
510
662
|
},
|
|
663
|
+
/**
|
|
664
|
+
* #action
|
|
665
|
+
* creates an svg export and save using FileSaver
|
|
666
|
+
*/
|
|
511
667
|
async exportSvg(opts = {}) {
|
|
512
668
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
513
669
|
const html = await renderToSvg(self, opts);
|
|
@@ -517,6 +673,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
517
673
|
}))
|
|
518
674
|
.actions(self => {
|
|
519
675
|
let cancelLastAnimation = () => { };
|
|
676
|
+
/**
|
|
677
|
+
* #action
|
|
678
|
+
* perform animated slide
|
|
679
|
+
*/
|
|
520
680
|
function slide(viewWidths) {
|
|
521
681
|
const [animate, cancelAnimation] = springAnimate(self.offsetPx, self.offsetPx + self.width * viewWidths, self.scrollTo);
|
|
522
682
|
cancelLastAnimation();
|
|
@@ -527,6 +687,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
527
687
|
})
|
|
528
688
|
.actions(self => {
|
|
529
689
|
let cancelLastAnimation = () => { };
|
|
690
|
+
/**
|
|
691
|
+
* #action
|
|
692
|
+
* perform animated zoom
|
|
693
|
+
*/
|
|
530
694
|
function zoom(targetBpPerPx) {
|
|
531
695
|
self.zoomTo(self.bpPerPx);
|
|
532
696
|
if (
|
|
@@ -548,17 +712,30 @@ export function stateModelFactory(pluginManager) {
|
|
|
548
712
|
return { zoom };
|
|
549
713
|
})
|
|
550
714
|
.views(self => ({
|
|
715
|
+
/**
|
|
716
|
+
* #getter
|
|
717
|
+
*/
|
|
551
718
|
get canShowCytobands() {
|
|
552
719
|
return self.displayedRegions.length === 1 && this.anyCytobandsExist;
|
|
553
720
|
},
|
|
721
|
+
/**
|
|
722
|
+
* #getter
|
|
723
|
+
*/
|
|
554
724
|
get showCytobands() {
|
|
555
725
|
return this.canShowCytobands && self.showCytobandsSetting;
|
|
556
726
|
},
|
|
727
|
+
/**
|
|
728
|
+
* #getter
|
|
729
|
+
*/
|
|
557
730
|
get anyCytobandsExist() {
|
|
558
731
|
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; });
|
|
732
|
+
return self.assemblyNames.some(a => { var _a, _b; return (_b = (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.cytobands) === null || _b === void 0 ? void 0 : _b.length; });
|
|
561
733
|
},
|
|
734
|
+
/**
|
|
735
|
+
* #getter
|
|
736
|
+
* the cytoband is displayed to the right of the chromosome name,
|
|
737
|
+
* and that offset is calculated manually with this method
|
|
738
|
+
*/
|
|
562
739
|
get cytobandOffset() {
|
|
563
740
|
return this.showCytobands
|
|
564
741
|
? measureText(self.displayedRegions[0].refName, 12) + 15
|
|
@@ -566,6 +743,10 @@ export function stateModelFactory(pluginManager) {
|
|
|
566
743
|
},
|
|
567
744
|
}))
|
|
568
745
|
.views(self => ({
|
|
746
|
+
/**
|
|
747
|
+
* #method
|
|
748
|
+
* return the view menu items
|
|
749
|
+
*/
|
|
569
750
|
menuItems() {
|
|
570
751
|
const { canShowCytobands, showCytobands } = self;
|
|
571
752
|
const session = getSession(self);
|
|
@@ -708,6 +889,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
708
889
|
let currentlyCalculatedStaticBlocks;
|
|
709
890
|
let stringifiedCurrentlyCalculatedStaticBlocks = '';
|
|
710
891
|
return {
|
|
892
|
+
/**
|
|
893
|
+
* #getter
|
|
894
|
+
* static blocks are an important concept jbrowse uses to avoid
|
|
895
|
+
* re-rendering when you scroll to the side. when you horizontally
|
|
896
|
+
* scroll to the right, old blocks to the left may be removed, and
|
|
897
|
+
* new blocks may be instantiated on the right. tracks may use the
|
|
898
|
+
* static blocks to render their data for the region represented by
|
|
899
|
+
* the block
|
|
900
|
+
*/
|
|
711
901
|
get staticBlocks() {
|
|
712
902
|
const ret = calculateStaticBlocks(self);
|
|
713
903
|
const sret = JSON.stringify(ret);
|
|
@@ -717,27 +907,48 @@ export function stateModelFactory(pluginManager) {
|
|
|
717
907
|
}
|
|
718
908
|
return currentlyCalculatedStaticBlocks;
|
|
719
909
|
},
|
|
910
|
+
/**
|
|
911
|
+
* #getter
|
|
912
|
+
* dynamic blocks represent the exact coordinates of the currently
|
|
913
|
+
* visible genome regions on the screen. they are similar to static
|
|
914
|
+
* blocks, but statcic blocks can go offscreen while dynamic blocks
|
|
915
|
+
* represent exactly what is on screen
|
|
916
|
+
*/
|
|
720
917
|
get dynamicBlocks() {
|
|
721
918
|
return calculateDynamicBlocks(self);
|
|
722
919
|
},
|
|
920
|
+
/**
|
|
921
|
+
* #getter
|
|
922
|
+
* rounded dynamic blocks are dynamic blocks without fractions of bp
|
|
923
|
+
*/
|
|
723
924
|
get roundedDynamicBlocks() {
|
|
724
|
-
return this.dynamicBlocks.contentBlocks.map(block => {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
};
|
|
730
|
-
});
|
|
925
|
+
return this.dynamicBlocks.contentBlocks.map(block => ({
|
|
926
|
+
...block,
|
|
927
|
+
start: Math.floor(block.start),
|
|
928
|
+
end: Math.ceil(block.end),
|
|
929
|
+
}));
|
|
731
930
|
},
|
|
931
|
+
/**
|
|
932
|
+
* #getter
|
|
933
|
+
* a single "combo-locstring" representing all the regions visible
|
|
934
|
+
* on the screen
|
|
935
|
+
*/
|
|
732
936
|
get visibleLocStrings() {
|
|
733
937
|
return calculateVisibleLocStrings(this.dynamicBlocks.contentBlocks);
|
|
734
938
|
},
|
|
939
|
+
/**
|
|
940
|
+
* #getter
|
|
941
|
+
* same as visibleLocStrings, but only updated every 300ms
|
|
942
|
+
*/
|
|
735
943
|
get coarseVisibleLocStrings() {
|
|
736
944
|
return calculateVisibleLocStrings(self.coarseDynamicBlocks);
|
|
737
945
|
},
|
|
738
946
|
};
|
|
739
947
|
})
|
|
740
948
|
.actions(self => ({
|
|
949
|
+
/**
|
|
950
|
+
* #action
|
|
951
|
+
*/
|
|
741
952
|
setCoarseDynamicBlocks(blocks) {
|
|
742
953
|
self.coarseDynamicBlocks = blocks.contentBlocks;
|
|
743
954
|
self.coarseTotalBp = blocks.totalBp;
|
|
@@ -752,6 +963,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
752
963
|
}))
|
|
753
964
|
.actions(self => ({
|
|
754
965
|
/**
|
|
966
|
+
* #action
|
|
755
967
|
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
756
968
|
* displayed region in the linear genome view
|
|
757
969
|
*
|
|
@@ -761,7 +973,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
761
973
|
moveTo(start, end) {
|
|
762
974
|
moveTo(self, start, end);
|
|
763
975
|
},
|
|
764
|
-
|
|
976
|
+
/**
|
|
977
|
+
* #action
|
|
978
|
+
* navigate to the given locstring
|
|
979
|
+
*
|
|
980
|
+
* @param locString - e.g. "chr1:1-100"
|
|
981
|
+
* @param optAssemblyName - (optional) the assembly name to use when navigating to the locstring
|
|
982
|
+
*/
|
|
983
|
+
async navToLocString(locString, optAssemblyName) {
|
|
765
984
|
const { assemblyNames } = self;
|
|
766
985
|
const { assemblyManager } = getSession(self);
|
|
767
986
|
const { isValidRefName } = assemblyManager;
|
|
@@ -771,6 +990,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
771
990
|
.split(/(\s+)/)
|
|
772
991
|
.map(f => f.trim())
|
|
773
992
|
.filter(f => !!f);
|
|
993
|
+
if (assemblyName) {
|
|
994
|
+
await assemblyManager.waitForAssembly(assemblyName);
|
|
995
|
+
}
|
|
774
996
|
// first try interpreting as a whitespace-separated sequence of
|
|
775
997
|
// multiple locstrings
|
|
776
998
|
try {
|
|
@@ -791,9 +1013,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
791
1013
|
throw e;
|
|
792
1014
|
}
|
|
793
1015
|
}
|
|
794
|
-
const locations = parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(region => {
|
|
1016
|
+
const locations = await Promise.all(parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(async (region) => {
|
|
795
1017
|
const asmName = region.assemblyName || assemblyName;
|
|
796
|
-
const asm = assemblyManager.
|
|
1018
|
+
const asm = await assemblyManager.waitForAssembly(asmName);
|
|
797
1019
|
const { refName } = region;
|
|
798
1020
|
if (!asm) {
|
|
799
1021
|
throw new Error(`assembly ${asmName} not found`);
|
|
@@ -806,7 +1028,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
806
1028
|
if (!canonicalRefName) {
|
|
807
1029
|
throw new Error(`Could not find refName ${refName} in ${asm.name}`);
|
|
808
1030
|
}
|
|
809
|
-
const parentRegion = regions.find(
|
|
1031
|
+
const parentRegion = regions.find(r => r.refName === canonicalRefName);
|
|
810
1032
|
if (!parentRegion) {
|
|
811
1033
|
throw new Error(`Could not find refName ${refName} in ${asmName}`);
|
|
812
1034
|
}
|
|
@@ -815,7 +1037,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
815
1037
|
assemblyName: asmName,
|
|
816
1038
|
parentRegion,
|
|
817
1039
|
};
|
|
818
|
-
});
|
|
1040
|
+
}));
|
|
819
1041
|
if (locations.length === 1) {
|
|
820
1042
|
const loc = locations[0];
|
|
821
1043
|
self.setDisplayedRegions([
|
|
@@ -836,6 +1058,7 @@ export function stateModelFactory(pluginManager) {
|
|
|
836
1058
|
}
|
|
837
1059
|
},
|
|
838
1060
|
/**
|
|
1061
|
+
* #action
|
|
839
1062
|
* Navigate to a location based on its refName and optionally start, end,
|
|
840
1063
|
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
841
1064
|
* from same refName. Only navigates to a location if it is entirely
|
|
@@ -844,11 +1067,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
844
1067
|
*
|
|
845
1068
|
* Throws an error if navigation was unsuccessful
|
|
846
1069
|
*
|
|
847
|
-
* @param
|
|
1070
|
+
* @param query - a proposed location to navigate to
|
|
848
1071
|
*/
|
|
849
1072
|
navTo(query) {
|
|
850
1073
|
this.navToMultiple([query]);
|
|
851
1074
|
},
|
|
1075
|
+
/**
|
|
1076
|
+
* #action
|
|
1077
|
+
*/
|
|
852
1078
|
navToMultiple(locations) {
|
|
853
1079
|
const firstLocation = locations[0];
|
|
854
1080
|
let { refName } = firstLocation;
|
|
@@ -950,6 +1176,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
950
1176
|
},
|
|
951
1177
|
}))
|
|
952
1178
|
.views(self => ({
|
|
1179
|
+
/**
|
|
1180
|
+
* #method
|
|
1181
|
+
*/
|
|
953
1182
|
rubberBandMenuItems() {
|
|
954
1183
|
return [
|
|
955
1184
|
{
|
|
@@ -967,10 +1196,14 @@ export function stateModelFactory(pluginManager) {
|
|
|
967
1196
|
},
|
|
968
1197
|
];
|
|
969
1198
|
},
|
|
1199
|
+
/**
|
|
1200
|
+
* #method
|
|
1201
|
+
*/
|
|
970
1202
|
bpToPx({ refName, coord, regionNumber, }) {
|
|
971
1203
|
return bpToPx({ refName, coord, regionNumber, self });
|
|
972
1204
|
},
|
|
973
1205
|
/**
|
|
1206
|
+
* #method
|
|
974
1207
|
* scrolls the view to center on the given bp. if that is not in any
|
|
975
1208
|
* of the displayed regions, does nothing
|
|
976
1209
|
* @param coord - basepair at which you want to center the view
|
|
@@ -987,9 +1220,15 @@ export function stateModelFactory(pluginManager) {
|
|
|
987
1220
|
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
|
|
988
1221
|
}
|
|
989
1222
|
},
|
|
1223
|
+
/**
|
|
1224
|
+
* #method
|
|
1225
|
+
*/
|
|
990
1226
|
pxToBp(px) {
|
|
991
1227
|
return pxToBp(self, px);
|
|
992
1228
|
},
|
|
1229
|
+
/**
|
|
1230
|
+
* #getter
|
|
1231
|
+
*/
|
|
993
1232
|
get centerLineInfo() {
|
|
994
1233
|
return self.displayedRegions.length
|
|
995
1234
|
? this.pxToBp(self.width / 2)
|