@jbrowse/plugin-linear-genome-view 2.0.0 → 2.0.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/LinearGenomeView/components/{VerticalGuides.d.ts → Gridlines.d.ts} +0 -0
- package/dist/LinearGenomeView/components/{VerticalGuides.js → Gridlines.js} +1 -1
- package/dist/LinearGenomeView/components/Gridlines.js.map +1 -0
- package/dist/LinearGenomeView/components/OverviewRubberBand.js +13 -10
- package/dist/LinearGenomeView/components/OverviewRubberBand.js.map +1 -1
- package/dist/LinearGenomeView/components/RubberBand.js +0 -1
- package/dist/LinearGenomeView/components/RubberBand.js.map +1 -1
- package/dist/LinearGenomeView/components/SequenceDialog.js +1 -1
- package/dist/LinearGenomeView/components/SequenceDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/TracksContainer.js +2 -2
- package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/dist/LinearGenomeView/index.d.ts +63 -76
- package/dist/LinearGenomeView/index.js +239 -365
- package/dist/LinearGenomeView/index.js.map +1 -1
- package/esm/LinearGenomeView/components/{VerticalGuides.d.ts → Gridlines.d.ts} +0 -0
- package/esm/LinearGenomeView/components/{VerticalGuides.js → Gridlines.js} +1 -1
- package/esm/LinearGenomeView/components/Gridlines.js.map +1 -0
- package/esm/LinearGenomeView/components/OverviewRubberBand.js +13 -10
- package/esm/LinearGenomeView/components/OverviewRubberBand.js.map +1 -1
- package/esm/LinearGenomeView/components/RubberBand.js +0 -1
- package/esm/LinearGenomeView/components/RubberBand.js.map +1 -1
- package/esm/LinearGenomeView/components/SequenceDialog.js +1 -1
- package/esm/LinearGenomeView/components/SequenceDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/TracksContainer.js +2 -2
- package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/esm/LinearGenomeView/index.d.ts +63 -76
- package/esm/LinearGenomeView/index.js +243 -389
- package/esm/LinearGenomeView/index.js.map +1 -1
- package/package.json +3 -3
- package/src/LinearGenomeView/components/{VerticalGuides.tsx → Gridlines.tsx} +0 -0
- package/src/LinearGenomeView/components/OverviewRubberBand.tsx +14 -19
- package/src/LinearGenomeView/components/RubberBand.tsx +0 -1
- package/src/LinearGenomeView/components/SequenceDialog.tsx +1 -1
- package/src/LinearGenomeView/components/TracksContainer.tsx +2 -2
- package/src/LinearGenomeView/index.test.ts +13 -36
- package/src/LinearGenomeView/index.tsx +360 -519
- package/dist/LinearGenomeView/components/VerticalGuides.js.map +0 -1
- package/esm/LinearGenomeView/components/VerticalGuides.js.map +0 -1
|
@@ -98,8 +98,9 @@ var tracks_1 = require("@jbrowse/core/util/tracks");
|
|
|
98
98
|
var mobx_1 = require("mobx");
|
|
99
99
|
var mobx_state_tree_1 = require("mobx-state-tree");
|
|
100
100
|
var Base1DViewModel_1 = __importDefault(require("@jbrowse/core/util/Base1DViewModel"));
|
|
101
|
-
var
|
|
101
|
+
var Base1DUtils_1 = require("@jbrowse/core/util/Base1DUtils");
|
|
102
102
|
var file_saver_1 = require("file-saver");
|
|
103
|
+
var clone_1 = __importDefault(require("clone"));
|
|
103
104
|
// icons
|
|
104
105
|
var Icons_1 = require("@jbrowse/core/ui/Icons");
|
|
105
106
|
var SyncAlt_1 = __importDefault(require("@mui/icons-material/SyncAlt"));
|
|
@@ -163,6 +164,7 @@ function stateModelFactory(pluginManager) {
|
|
|
163
164
|
var setting = localStorageGetItem('lgv-showCytobands');
|
|
164
165
|
return setting !== undefined && setting !== null ? !!+setting : true;
|
|
165
166
|
}),
|
|
167
|
+
showGridlines: true,
|
|
166
168
|
}))
|
|
167
169
|
.volatile(function () { return ({
|
|
168
170
|
volatileWidth: undefined,
|
|
@@ -280,71 +282,6 @@ function stateModelFactory(pluginManager) {
|
|
|
280
282
|
tracks: self.tracks,
|
|
281
283
|
};
|
|
282
284
|
},
|
|
283
|
-
bpToPx: function (_a) {
|
|
284
|
-
var refName = _a.refName, coord = _a.coord, regionNumber = _a.regionNumber;
|
|
285
|
-
return (0, util_1.viewBpToPx)({ refName: refName, coord: coord, regionNumber: regionNumber, self: self });
|
|
286
|
-
},
|
|
287
|
-
/**
|
|
288
|
-
*
|
|
289
|
-
* @param px - px in the view area, return value is the displayed regions
|
|
290
|
-
* @returns BpOffset of the displayed region that it lands in
|
|
291
|
-
*/
|
|
292
|
-
pxToBp: function (px) {
|
|
293
|
-
var bpSoFar = 0;
|
|
294
|
-
var bp = (self.offsetPx + px) * self.bpPerPx;
|
|
295
|
-
var n = self.displayedRegions.length;
|
|
296
|
-
if (bp < 0) {
|
|
297
|
-
var region = self.displayedRegions[0];
|
|
298
|
-
var offset = bp;
|
|
299
|
-
var snap = (0, mobx_state_tree_1.getSnapshot)(region);
|
|
300
|
-
return __assign(__assign({}, snap), { oob: true, coord: region.reversed
|
|
301
|
-
? Math.floor(region.end - offset) + 1
|
|
302
|
-
: Math.floor(region.start + offset) + 1, offset: offset, index: 0 });
|
|
303
|
-
}
|
|
304
|
-
var interRegionPaddingBp = self.interRegionPaddingWidth * self.bpPerPx;
|
|
305
|
-
var minimumBlockBp = self.minimumBlockWidth * self.bpPerPx;
|
|
306
|
-
for (var index = 0; index < self.displayedRegions.length; index += 1) {
|
|
307
|
-
var region = self.displayedRegions[index];
|
|
308
|
-
var len = region.end - region.start;
|
|
309
|
-
var offset = bp - bpSoFar;
|
|
310
|
-
if (len + bpSoFar > bp && bpSoFar <= bp) {
|
|
311
|
-
var snap = (0, mobx_state_tree_1.getSnapshot)(region);
|
|
312
|
-
return __assign(__assign({}, snap), { oob: false, offset: offset, coord: region.reversed
|
|
313
|
-
? Math.floor(region.end - offset) + 1
|
|
314
|
-
: Math.floor(region.start + offset) + 1, index: index });
|
|
315
|
-
}
|
|
316
|
-
// add the interRegionPaddingWidth if the boundary is in the screen
|
|
317
|
-
// e.g. offset>0 && offset<width
|
|
318
|
-
if (region.end - region.start > minimumBlockBp &&
|
|
319
|
-
offset / self.bpPerPx > 0 &&
|
|
320
|
-
offset / self.bpPerPx < self.width) {
|
|
321
|
-
bpSoFar += len + interRegionPaddingBp;
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
bpSoFar += len;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
if (bp >= bpSoFar) {
|
|
328
|
-
var region = self.displayedRegions[n - 1];
|
|
329
|
-
var len = region.end - region.start;
|
|
330
|
-
var offset = bp - bpSoFar + len;
|
|
331
|
-
var snap = (0, mobx_state_tree_1.getSnapshot)(region);
|
|
332
|
-
return __assign(__assign({}, snap), { oob: true, offset: offset, coord: region.reversed
|
|
333
|
-
? Math.floor(region.end - offset) + 1
|
|
334
|
-
: Math.floor(region.start + offset) + 1, index: n - 1 });
|
|
335
|
-
}
|
|
336
|
-
return {
|
|
337
|
-
coord: 0,
|
|
338
|
-
index: 0,
|
|
339
|
-
refName: '',
|
|
340
|
-
oob: true,
|
|
341
|
-
assemblyName: '',
|
|
342
|
-
offset: 0,
|
|
343
|
-
start: 0,
|
|
344
|
-
end: 0,
|
|
345
|
-
reversed: false,
|
|
346
|
-
};
|
|
347
|
-
},
|
|
348
285
|
getTrack: function (id) {
|
|
349
286
|
return self.tracks.find(function (t) { return t.configuration.trackId === id; });
|
|
350
287
|
},
|
|
@@ -395,11 +332,6 @@ function stateModelFactory(pluginManager) {
|
|
|
395
332
|
});
|
|
396
333
|
return allActions;
|
|
397
334
|
},
|
|
398
|
-
get centerLineInfo() {
|
|
399
|
-
return self.displayedRegions.length
|
|
400
|
-
? this.pxToBp(self.width / 2)
|
|
401
|
-
: undefined;
|
|
402
|
-
},
|
|
403
335
|
}); })
|
|
404
336
|
.actions(function (self) { return ({
|
|
405
337
|
setShowCytobands: function (flag) {
|
|
@@ -421,6 +353,9 @@ function stateModelFactory(pluginManager) {
|
|
|
421
353
|
toggleNoTracksActive: function () {
|
|
422
354
|
self.hideNoTracksActive = !self.hideNoTracksActive;
|
|
423
355
|
},
|
|
356
|
+
toggleShowGridlines: function () {
|
|
357
|
+
self.showGridlines = !self.showGridlines;
|
|
358
|
+
},
|
|
424
359
|
scrollTo: function (offsetPx) {
|
|
425
360
|
var newOffsetPx = (0, util_1.clamp)(offsetPx, self.minOffset, self.maxOffset);
|
|
426
361
|
self.offsetPx = newOffsetPx;
|
|
@@ -562,230 +497,6 @@ function stateModelFactory(pluginManager) {
|
|
|
562
497
|
}
|
|
563
498
|
throw new Error("invalid track selector type ".concat(self.trackSelectorType));
|
|
564
499
|
},
|
|
565
|
-
navToLocString: function (locString, optAssemblyName) {
|
|
566
|
-
var assemblyNames = self.assemblyNames;
|
|
567
|
-
var assemblyManager = (0, util_1.getSession)(self).assemblyManager;
|
|
568
|
-
var isValidRefName = assemblyManager.isValidRefName;
|
|
569
|
-
var assemblyName = optAssemblyName || assemblyNames[0];
|
|
570
|
-
var parsedLocStrings;
|
|
571
|
-
var inputs = locString
|
|
572
|
-
.split(/(\s+)/)
|
|
573
|
-
.map(function (f) { return f.trim(); })
|
|
574
|
-
.filter(function (f) { return !!f; });
|
|
575
|
-
// first try interpreting as a whitespace-separated sequence of
|
|
576
|
-
// multiple locstrings
|
|
577
|
-
try {
|
|
578
|
-
parsedLocStrings = inputs.map(function (l) {
|
|
579
|
-
return (0, util_1.parseLocString)(l, function (ref) { return isValidRefName(ref, assemblyName); });
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
catch (e) {
|
|
583
|
-
// if this fails, try interpreting as a whitespace-separated refname,
|
|
584
|
-
// start, end if start and end are integer inputs
|
|
585
|
-
var _a = __read(inputs, 3), refName = _a[0], start = _a[1], end = _a[2];
|
|
586
|
-
if ("".concat(e).match(/Unknown reference sequence/) &&
|
|
587
|
-
Number.isInteger(+start) &&
|
|
588
|
-
Number.isInteger(+end)) {
|
|
589
|
-
parsedLocStrings = [
|
|
590
|
-
(0, util_1.parseLocString)(refName + ':' + start + '..' + end, function (ref) {
|
|
591
|
-
return isValidRefName(ref, assemblyName);
|
|
592
|
-
}),
|
|
593
|
-
];
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
throw e;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
var locations = parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(function (region) {
|
|
600
|
-
var asmName = region.assemblyName || assemblyName;
|
|
601
|
-
var asm = assemblyManager.get(asmName);
|
|
602
|
-
var refName = region.refName;
|
|
603
|
-
if (!asm) {
|
|
604
|
-
throw new Error("assembly ".concat(asmName, " not found"));
|
|
605
|
-
}
|
|
606
|
-
var regions = asm.regions;
|
|
607
|
-
if (!regions) {
|
|
608
|
-
throw new Error("regions not loaded yet for ".concat(asmName));
|
|
609
|
-
}
|
|
610
|
-
var canonicalRefName = asm.getCanonicalRefName(region.refName);
|
|
611
|
-
if (!canonicalRefName) {
|
|
612
|
-
throw new Error("Could not find refName ".concat(refName, " in ").concat(asm.name));
|
|
613
|
-
}
|
|
614
|
-
var parentRegion = regions.find(function (region) { return region.refName === canonicalRefName; });
|
|
615
|
-
if (!parentRegion) {
|
|
616
|
-
throw new Error("Could not find refName ".concat(refName, " in ").concat(asmName));
|
|
617
|
-
}
|
|
618
|
-
return __assign(__assign({}, region), { assemblyName: asmName, parentRegion: parentRegion });
|
|
619
|
-
});
|
|
620
|
-
if (locations.length === 1) {
|
|
621
|
-
var loc = locations[0];
|
|
622
|
-
this.setDisplayedRegions([
|
|
623
|
-
__assign({ reversed: loc.reversed }, loc.parentRegion),
|
|
624
|
-
]);
|
|
625
|
-
var start = loc.start, end = loc.end, parentRegion = loc.parentRegion;
|
|
626
|
-
this.navTo(__assign(__assign({}, loc), { start: (0, util_1.clamp)(start !== null && start !== void 0 ? start : 0, 0, parentRegion.end), end: (0, util_1.clamp)(end !== null && end !== void 0 ? end : parentRegion.end, 0, parentRegion.end) }));
|
|
627
|
-
}
|
|
628
|
-
else {
|
|
629
|
-
this.setDisplayedRegions(
|
|
630
|
-
// @ts-ignore
|
|
631
|
-
locations.map(function (r) { return (r.start === undefined ? r.parentRegion : r); }));
|
|
632
|
-
this.showAllRegions();
|
|
633
|
-
}
|
|
634
|
-
},
|
|
635
|
-
/**
|
|
636
|
-
* Navigate to a location based on its refName and optionally start, end,
|
|
637
|
-
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
638
|
-
* from same refName. Only navigates to a location if it is entirely
|
|
639
|
-
* within a displayedRegion. Navigates to the first matching location
|
|
640
|
-
* encountered.
|
|
641
|
-
*
|
|
642
|
-
* Throws an error if navigation was unsuccessful
|
|
643
|
-
*
|
|
644
|
-
* @param location - a proposed location to navigate to
|
|
645
|
-
*/
|
|
646
|
-
navTo: function (query) {
|
|
647
|
-
this.navToMultiple([query]);
|
|
648
|
-
},
|
|
649
|
-
navToMultiple: function (locations) {
|
|
650
|
-
var firstLocation = locations[0];
|
|
651
|
-
var refName = firstLocation.refName;
|
|
652
|
-
var start = firstLocation.start, end = firstLocation.end, _a = firstLocation.assemblyName, assemblyName = _a === void 0 ? self.assemblyNames[0] : _a;
|
|
653
|
-
if (start !== undefined && end !== undefined && start > end) {
|
|
654
|
-
throw new Error("start \"".concat(start + 1, "\" is greater than end \"").concat(end, "\""));
|
|
655
|
-
}
|
|
656
|
-
var session = (0, util_1.getSession)(self);
|
|
657
|
-
var assemblyManager = session.assemblyManager;
|
|
658
|
-
var assembly = assemblyManager.get(assemblyName);
|
|
659
|
-
if (assembly) {
|
|
660
|
-
var canonicalRefName = assembly.getCanonicalRefName(refName);
|
|
661
|
-
if (canonicalRefName) {
|
|
662
|
-
refName = canonicalRefName;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
var s = start;
|
|
666
|
-
var e = end;
|
|
667
|
-
var refNameMatched = false;
|
|
668
|
-
var predicate = function (r) {
|
|
669
|
-
if (refName === r.refName) {
|
|
670
|
-
refNameMatched = true;
|
|
671
|
-
if (s === undefined) {
|
|
672
|
-
s = r.start;
|
|
673
|
-
}
|
|
674
|
-
if (e === undefined) {
|
|
675
|
-
e = r.end;
|
|
676
|
-
}
|
|
677
|
-
if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
|
|
678
|
-
return true;
|
|
679
|
-
}
|
|
680
|
-
s = start;
|
|
681
|
-
e = end;
|
|
682
|
-
}
|
|
683
|
-
return false;
|
|
684
|
-
};
|
|
685
|
-
var lastIndex = (0, util_1.findLastIndex)(self.displayedRegions, predicate);
|
|
686
|
-
var index;
|
|
687
|
-
while (index !== lastIndex) {
|
|
688
|
-
try {
|
|
689
|
-
var previousIndex = index;
|
|
690
|
-
index = self.displayedRegions
|
|
691
|
-
.slice(previousIndex === undefined ? 0 : previousIndex + 1)
|
|
692
|
-
.findIndex(predicate);
|
|
693
|
-
if (previousIndex !== undefined) {
|
|
694
|
-
index += previousIndex + 1;
|
|
695
|
-
}
|
|
696
|
-
if (!refNameMatched) {
|
|
697
|
-
throw new Error("could not find a region with refName \"".concat(refName, "\""));
|
|
698
|
-
}
|
|
699
|
-
if (s === undefined) {
|
|
700
|
-
throw new Error("could not find a region with refName \"".concat(refName, "\" that contained an end position ").concat(e));
|
|
701
|
-
}
|
|
702
|
-
if (e === undefined) {
|
|
703
|
-
throw new Error("could not find a region with refName \"".concat(refName, "\" that contained a start position ").concat(s + 1));
|
|
704
|
-
}
|
|
705
|
-
if (index === -1) {
|
|
706
|
-
throw new Error("could not find a region that completely contained \"".concat((0, util_1.assembleLocString)(firstLocation), "\""));
|
|
707
|
-
}
|
|
708
|
-
if (locations.length === 1) {
|
|
709
|
-
var f = self.displayedRegions[index];
|
|
710
|
-
this.moveTo({ index: index, offset: f.reversed ? f.end - e : s - f.start }, { index: index, offset: f.reversed ? f.end - s : e - f.start });
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
var locationIndex = 0;
|
|
714
|
-
var locationStart = 0;
|
|
715
|
-
var locationEnd = 0;
|
|
716
|
-
for (locationIndex; locationIndex < locations.length; locationIndex++) {
|
|
717
|
-
var location_1 = locations[locationIndex];
|
|
718
|
-
var region = self.displayedRegions[index + locationIndex];
|
|
719
|
-
locationStart = location_1.start || region.start;
|
|
720
|
-
locationEnd = location_1.end || region.end;
|
|
721
|
-
if (location_1.refName !== region.refName) {
|
|
722
|
-
throw new Error("Entered location ".concat((0, util_1.assembleLocString)(location_1), " does not match with displayed regions"));
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
locationIndex -= 1;
|
|
726
|
-
var startDisplayedRegion = self.displayedRegions[index];
|
|
727
|
-
var endDisplayedRegion = self.displayedRegions[index + locationIndex];
|
|
728
|
-
this.moveTo({
|
|
729
|
-
index: index,
|
|
730
|
-
offset: startDisplayedRegion.reversed
|
|
731
|
-
? startDisplayedRegion.end - e
|
|
732
|
-
: s - startDisplayedRegion.start,
|
|
733
|
-
}, {
|
|
734
|
-
index: index + locationIndex,
|
|
735
|
-
offset: endDisplayedRegion.reversed
|
|
736
|
-
? endDisplayedRegion.end - locationStart
|
|
737
|
-
: locationEnd - endDisplayedRegion.start,
|
|
738
|
-
});
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
catch (error) {
|
|
742
|
-
if (index === lastIndex) {
|
|
743
|
-
throw error;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
},
|
|
748
|
-
/**
|
|
749
|
-
* Navigate to a location based on user clicking and dragging on the
|
|
750
|
-
* overview scale bar to select a region to zoom into.
|
|
751
|
-
* Can handle if there are multiple displayedRegions from same refName.
|
|
752
|
-
* Only navigates to a location if it is entirely within a displayedRegion.
|
|
753
|
-
*
|
|
754
|
-
* @param leftPx- `object as {start, end, index, offset}`, offset = start of user drag
|
|
755
|
-
* @param rightPx- `object as {start, end, index, offset}`, offset = end of user drag
|
|
756
|
-
*/
|
|
757
|
-
zoomToDisplayedRegions: function (leftPx, rightPx) {
|
|
758
|
-
var _a;
|
|
759
|
-
if (leftPx === undefined || rightPx === undefined) {
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
762
|
-
var singleRefSeq = leftPx.refName === rightPx.refName && leftPx.index === rightPx.index;
|
|
763
|
-
// zooming into one displayed Region
|
|
764
|
-
if ((singleRefSeq && rightPx.offset < leftPx.offset) ||
|
|
765
|
-
leftPx.index > rightPx.index) {
|
|
766
|
-
;
|
|
767
|
-
_a = __read([rightPx, leftPx], 2), leftPx = _a[0], rightPx = _a[1];
|
|
768
|
-
}
|
|
769
|
-
var startOffset = {
|
|
770
|
-
start: leftPx.start,
|
|
771
|
-
end: leftPx.end,
|
|
772
|
-
index: leftPx.index,
|
|
773
|
-
offset: leftPx.offset,
|
|
774
|
-
};
|
|
775
|
-
var endOffset = {
|
|
776
|
-
start: rightPx.start,
|
|
777
|
-
end: rightPx.end,
|
|
778
|
-
index: rightPx.index,
|
|
779
|
-
offset: rightPx.offset,
|
|
780
|
-
};
|
|
781
|
-
if (startOffset && endOffset) {
|
|
782
|
-
this.moveTo(startOffset, endOffset);
|
|
783
|
-
}
|
|
784
|
-
else {
|
|
785
|
-
var session = (0, util_1.getSession)(self);
|
|
786
|
-
session.notify('No regions found to navigate to', 'warning');
|
|
787
|
-
}
|
|
788
|
-
},
|
|
789
500
|
/**
|
|
790
501
|
* Helper method for the fetchSequence.
|
|
791
502
|
* Retrieves the corresponding regions that were selected by the rubberband
|
|
@@ -798,87 +509,23 @@ function stateModelFactory(pluginManager) {
|
|
|
798
509
|
var snap = (0, mobx_state_tree_1.getSnapshot)(self);
|
|
799
510
|
var simView = Base1DViewModel_1.default.create(__assign(__assign({}, snap), { interRegionPaddingWidth: self.interRegionPaddingWidth }));
|
|
800
511
|
simView.setVolatileWidth(self.width);
|
|
801
|
-
simView.
|
|
512
|
+
simView.moveTo(leftOffset, rightOffset);
|
|
802
513
|
return simView.dynamicBlocks.contentBlocks.map(function (region) { return (__assign(__assign({}, region), { start: Math.floor(region.start), end: Math.ceil(region.end) })); });
|
|
803
514
|
},
|
|
804
515
|
// schedule something to be run after the next time displayedRegions is set
|
|
805
516
|
afterDisplayedRegionsSet: function (cb) {
|
|
806
517
|
self.afterDisplayedRegionsSetCallbacks.push(cb);
|
|
807
518
|
},
|
|
808
|
-
/**
|
|
809
|
-
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
810
|
-
* displayed region in the linear genome view
|
|
811
|
-
*
|
|
812
|
-
* @param start - object as `{start, end, offset, index}`
|
|
813
|
-
* @param end - object as `{start, end, offset, index}`
|
|
814
|
-
*/
|
|
815
|
-
moveTo: function (start, end) {
|
|
816
|
-
// find locations in the modellist
|
|
817
|
-
var bpSoFar = 0;
|
|
818
|
-
if (start.index === end.index) {
|
|
819
|
-
bpSoFar += end.offset - start.offset;
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
var s = self.displayedRegions[start.index];
|
|
823
|
-
bpSoFar += s.end - s.start - start.offset;
|
|
824
|
-
if (end.index - start.index >= 2) {
|
|
825
|
-
for (var i = start.index + 1; i < end.index; i += 1) {
|
|
826
|
-
bpSoFar +=
|
|
827
|
-
self.displayedRegions[i].end - self.displayedRegions[i].start;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
bpSoFar += end.offset;
|
|
831
|
-
}
|
|
832
|
-
var targetBpPerPx = bpSoFar /
|
|
833
|
-
(self.width -
|
|
834
|
-
self.interRegionPaddingWidth * (end.index - start.index));
|
|
835
|
-
var newBpPerPx = self.zoomTo(targetBpPerPx);
|
|
836
|
-
// If our target bpPerPx was smaller than the allowed minBpPerPx, adjust
|
|
837
|
-
// the scroll so the requested range is in the middle of the screen
|
|
838
|
-
var extraBp = 0;
|
|
839
|
-
if (targetBpPerPx < newBpPerPx) {
|
|
840
|
-
extraBp = ((newBpPerPx - targetBpPerPx) * self.width) / 2;
|
|
841
|
-
}
|
|
842
|
-
var bpToStart = -extraBp;
|
|
843
|
-
for (var i = 0; i < self.displayedRegions.length; i += 1) {
|
|
844
|
-
var region = self.displayedRegions[i];
|
|
845
|
-
if (start.index === i) {
|
|
846
|
-
bpToStart += start.offset;
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
else {
|
|
850
|
-
bpToStart += region.end - region.start;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
self.scrollTo(Math.round(bpToStart / self.bpPerPx) +
|
|
854
|
-
self.interRegionPaddingWidth * start.index);
|
|
855
|
-
},
|
|
856
519
|
horizontalScroll: function (distance) {
|
|
857
520
|
var oldOffsetPx = self.offsetPx;
|
|
858
521
|
// newOffsetPx is the actual offset after the scroll is clamped
|
|
859
522
|
var newOffsetPx = self.scrollTo(self.offsetPx + distance);
|
|
860
523
|
return newOffsetPx - oldOffsetPx;
|
|
861
524
|
},
|
|
862
|
-
/**
|
|
863
|
-
* scrolls the view to center on the given bp. if that is not in any
|
|
864
|
-
* of the displayed regions, does nothing
|
|
865
|
-
* @param bp - basepair at which you want to center the view
|
|
866
|
-
* @param refName - refName of the displayedRegion you are centering at
|
|
867
|
-
* @param regionIndex - index of the displayedRegion
|
|
868
|
-
*/
|
|
869
|
-
centerAt: function (bp, refName, regionIndex) {
|
|
870
|
-
var centerPx = self.bpToPx({
|
|
871
|
-
refName: refName,
|
|
872
|
-
coord: bp,
|
|
873
|
-
regionNumber: regionIndex,
|
|
874
|
-
});
|
|
875
|
-
if (centerPx) {
|
|
876
|
-
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
|
|
877
|
-
}
|
|
878
|
-
},
|
|
879
525
|
center: function () {
|
|
880
526
|
var centerBp = self.totalBp / 2;
|
|
881
|
-
|
|
527
|
+
var centerPx = centerBp / self.bpPerPx;
|
|
528
|
+
self.scrollTo(Math.round(centerPx - self.width / 2));
|
|
882
529
|
},
|
|
883
530
|
showAllRegions: function () {
|
|
884
531
|
self.zoomTo(self.maxBpPerPx);
|
|
@@ -1034,6 +681,13 @@ function stateModelFactory(pluginManager) {
|
|
|
1034
681
|
checked: !self.hideNoTracksActive,
|
|
1035
682
|
onClick: self.toggleNoTracksActive,
|
|
1036
683
|
},
|
|
684
|
+
{
|
|
685
|
+
label: 'Show gridlines',
|
|
686
|
+
icon: Visibility_1.default,
|
|
687
|
+
type: 'checkbox',
|
|
688
|
+
checked: self.showGridlines,
|
|
689
|
+
onClick: self.toggleShowGridlines,
|
|
690
|
+
},
|
|
1037
691
|
{
|
|
1038
692
|
label: 'Track labels',
|
|
1039
693
|
icon: Label_1.default,
|
|
@@ -1163,6 +817,199 @@ function stateModelFactory(pluginManager) {
|
|
|
1163
817
|
});
|
|
1164
818
|
});
|
|
1165
819
|
},
|
|
820
|
+
/**
|
|
821
|
+
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
822
|
+
* displayed region in the linear genome view
|
|
823
|
+
*
|
|
824
|
+
* @param start - object as `{start, end, offset, index}`
|
|
825
|
+
* @param end - object as `{start, end, offset, index}`
|
|
826
|
+
*/
|
|
827
|
+
moveTo: function (start, end) {
|
|
828
|
+
(0, Base1DUtils_1.moveTo)(self, start, end);
|
|
829
|
+
},
|
|
830
|
+
navToLocString: function (locString, optAssemblyName) {
|
|
831
|
+
var assemblyNames = self.assemblyNames;
|
|
832
|
+
var assemblyManager = (0, util_1.getSession)(self).assemblyManager;
|
|
833
|
+
var isValidRefName = assemblyManager.isValidRefName;
|
|
834
|
+
var assemblyName = optAssemblyName || assemblyNames[0];
|
|
835
|
+
var parsedLocStrings;
|
|
836
|
+
var inputs = locString
|
|
837
|
+
.split(/(\s+)/)
|
|
838
|
+
.map(function (f) { return f.trim(); })
|
|
839
|
+
.filter(function (f) { return !!f; });
|
|
840
|
+
// first try interpreting as a whitespace-separated sequence of
|
|
841
|
+
// multiple locstrings
|
|
842
|
+
try {
|
|
843
|
+
parsedLocStrings = inputs.map(function (l) {
|
|
844
|
+
return (0, util_1.parseLocString)(l, function (ref) { return isValidRefName(ref, assemblyName); });
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
catch (e) {
|
|
848
|
+
// if this fails, try interpreting as a whitespace-separated refname,
|
|
849
|
+
// start, end if start and end are integer inputs
|
|
850
|
+
var _a = __read(inputs, 3), refName = _a[0], start = _a[1], end = _a[2];
|
|
851
|
+
if ("".concat(e).match(/Unknown reference sequence/) &&
|
|
852
|
+
Number.isInteger(+start) &&
|
|
853
|
+
Number.isInteger(+end)) {
|
|
854
|
+
parsedLocStrings = [
|
|
855
|
+
(0, util_1.parseLocString)(refName + ':' + start + '..' + end, function (ref) {
|
|
856
|
+
return isValidRefName(ref, assemblyName);
|
|
857
|
+
}),
|
|
858
|
+
];
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
throw e;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
var locations = parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(function (region) {
|
|
865
|
+
var asmName = region.assemblyName || assemblyName;
|
|
866
|
+
var asm = assemblyManager.get(asmName);
|
|
867
|
+
var refName = region.refName;
|
|
868
|
+
if (!asm) {
|
|
869
|
+
throw new Error("assembly ".concat(asmName, " not found"));
|
|
870
|
+
}
|
|
871
|
+
var regions = asm.regions;
|
|
872
|
+
if (!regions) {
|
|
873
|
+
throw new Error("regions not loaded yet for ".concat(asmName));
|
|
874
|
+
}
|
|
875
|
+
var canonicalRefName = asm.getCanonicalRefName(region.refName);
|
|
876
|
+
if (!canonicalRefName) {
|
|
877
|
+
throw new Error("Could not find refName ".concat(refName, " in ").concat(asm.name));
|
|
878
|
+
}
|
|
879
|
+
var parentRegion = regions.find(function (region) { return region.refName === canonicalRefName; });
|
|
880
|
+
if (!parentRegion) {
|
|
881
|
+
throw new Error("Could not find refName ".concat(refName, " in ").concat(asmName));
|
|
882
|
+
}
|
|
883
|
+
return __assign(__assign({}, region), { assemblyName: asmName, parentRegion: parentRegion });
|
|
884
|
+
});
|
|
885
|
+
if (locations.length === 1) {
|
|
886
|
+
var loc = locations[0];
|
|
887
|
+
self.setDisplayedRegions([
|
|
888
|
+
__assign({ reversed: loc.reversed }, loc.parentRegion),
|
|
889
|
+
]);
|
|
890
|
+
var start = loc.start, end = loc.end, parentRegion = loc.parentRegion;
|
|
891
|
+
this.navTo(__assign(__assign({}, loc), { start: (0, util_1.clamp)(start !== null && start !== void 0 ? start : 0, 0, parentRegion.end), end: (0, util_1.clamp)(end !== null && end !== void 0 ? end : parentRegion.end, 0, parentRegion.end) }));
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
self.setDisplayedRegions(
|
|
895
|
+
// @ts-ignore
|
|
896
|
+
locations.map(function (r) { return (r.start === undefined ? r.parentRegion : r); }));
|
|
897
|
+
self.showAllRegions();
|
|
898
|
+
}
|
|
899
|
+
},
|
|
900
|
+
/**
|
|
901
|
+
* Navigate to a location based on its refName and optionally start, end,
|
|
902
|
+
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
903
|
+
* from same refName. Only navigates to a location if it is entirely
|
|
904
|
+
* within a displayedRegion. Navigates to the first matching location
|
|
905
|
+
* encountered.
|
|
906
|
+
*
|
|
907
|
+
* Throws an error if navigation was unsuccessful
|
|
908
|
+
*
|
|
909
|
+
* @param location - a proposed location to navigate to
|
|
910
|
+
*/
|
|
911
|
+
navTo: function (query) {
|
|
912
|
+
this.navToMultiple([query]);
|
|
913
|
+
},
|
|
914
|
+
navToMultiple: function (locations) {
|
|
915
|
+
var firstLocation = locations[0];
|
|
916
|
+
var refName = firstLocation.refName;
|
|
917
|
+
var start = firstLocation.start, end = firstLocation.end, _a = firstLocation.assemblyName, assemblyName = _a === void 0 ? self.assemblyNames[0] : _a;
|
|
918
|
+
if (start !== undefined && end !== undefined && start > end) {
|
|
919
|
+
throw new Error("start \"".concat(start + 1, "\" is greater than end \"").concat(end, "\""));
|
|
920
|
+
}
|
|
921
|
+
var session = (0, util_1.getSession)(self);
|
|
922
|
+
var assemblyManager = session.assemblyManager;
|
|
923
|
+
var assembly = assemblyManager.get(assemblyName);
|
|
924
|
+
if (assembly) {
|
|
925
|
+
var canonicalRefName = assembly.getCanonicalRefName(refName);
|
|
926
|
+
if (canonicalRefName) {
|
|
927
|
+
refName = canonicalRefName;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
var s = start;
|
|
931
|
+
var e = end;
|
|
932
|
+
var refNameMatched = false;
|
|
933
|
+
var predicate = function (r) {
|
|
934
|
+
if (refName === r.refName) {
|
|
935
|
+
refNameMatched = true;
|
|
936
|
+
if (s === undefined) {
|
|
937
|
+
s = r.start;
|
|
938
|
+
}
|
|
939
|
+
if (e === undefined) {
|
|
940
|
+
e = r.end;
|
|
941
|
+
}
|
|
942
|
+
if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
|
|
943
|
+
return true;
|
|
944
|
+
}
|
|
945
|
+
s = start;
|
|
946
|
+
e = end;
|
|
947
|
+
}
|
|
948
|
+
return false;
|
|
949
|
+
};
|
|
950
|
+
var lastIndex = (0, util_1.findLastIndex)(self.displayedRegions, predicate);
|
|
951
|
+
var index;
|
|
952
|
+
while (index !== lastIndex) {
|
|
953
|
+
try {
|
|
954
|
+
var previousIndex = index;
|
|
955
|
+
index = self.displayedRegions
|
|
956
|
+
.slice(previousIndex === undefined ? 0 : previousIndex + 1)
|
|
957
|
+
.findIndex(predicate);
|
|
958
|
+
if (previousIndex !== undefined) {
|
|
959
|
+
index += previousIndex + 1;
|
|
960
|
+
}
|
|
961
|
+
if (!refNameMatched) {
|
|
962
|
+
throw new Error("could not find a region with refName \"".concat(refName, "\""));
|
|
963
|
+
}
|
|
964
|
+
if (s === undefined) {
|
|
965
|
+
throw new Error("could not find a region with refName \"".concat(refName, "\" that contained an end position ").concat(e));
|
|
966
|
+
}
|
|
967
|
+
if (e === undefined) {
|
|
968
|
+
throw new Error("could not find a region with refName \"".concat(refName, "\" that contained a start position ").concat(s + 1));
|
|
969
|
+
}
|
|
970
|
+
if (index === -1) {
|
|
971
|
+
throw new Error("could not find a region that completely contained \"".concat((0, util_1.assembleLocString)(firstLocation), "\""));
|
|
972
|
+
}
|
|
973
|
+
if (locations.length === 1) {
|
|
974
|
+
var f = self.displayedRegions[index];
|
|
975
|
+
this.moveTo({ index: index, offset: f.reversed ? f.end - e : s - f.start }, { index: index, offset: f.reversed ? f.end - s : e - f.start });
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
var locationIndex = 0;
|
|
979
|
+
var locationStart = 0;
|
|
980
|
+
var locationEnd = 0;
|
|
981
|
+
for (locationIndex; locationIndex < locations.length; locationIndex++) {
|
|
982
|
+
var location_1 = locations[locationIndex];
|
|
983
|
+
var region = self.displayedRegions[index + locationIndex];
|
|
984
|
+
locationStart = location_1.start || region.start;
|
|
985
|
+
locationEnd = location_1.end || region.end;
|
|
986
|
+
if (location_1.refName !== region.refName) {
|
|
987
|
+
throw new Error("Entered location ".concat((0, util_1.assembleLocString)(location_1), " does not match with displayed regions"));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
locationIndex -= 1;
|
|
991
|
+
var startDisplayedRegion = self.displayedRegions[index];
|
|
992
|
+
var endDisplayedRegion = self.displayedRegions[index + locationIndex];
|
|
993
|
+
this.moveTo({
|
|
994
|
+
index: index,
|
|
995
|
+
offset: startDisplayedRegion.reversed
|
|
996
|
+
? startDisplayedRegion.end - e
|
|
997
|
+
: s - startDisplayedRegion.start,
|
|
998
|
+
}, {
|
|
999
|
+
index: index + locationIndex,
|
|
1000
|
+
offset: endDisplayedRegion.reversed
|
|
1001
|
+
? endDisplayedRegion.end - locationStart
|
|
1002
|
+
: locationEnd - endDisplayedRegion.start,
|
|
1003
|
+
});
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
catch (error) {
|
|
1007
|
+
if (index === lastIndex) {
|
|
1008
|
+
throw error;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
},
|
|
1166
1013
|
}); })
|
|
1167
1014
|
.views(function (self) { return ({
|
|
1168
1015
|
rubberBandMenuItems: function () {
|
|
@@ -1172,9 +1019,7 @@ function stateModelFactory(pluginManager) {
|
|
|
1172
1019
|
icon: ZoomIn_1.default,
|
|
1173
1020
|
onClick: function () {
|
|
1174
1021
|
var leftOffset = self.leftOffset, rightOffset = self.rightOffset;
|
|
1175
|
-
|
|
1176
|
-
self.moveTo(leftOffset, rightOffset);
|
|
1177
|
-
}
|
|
1022
|
+
self.moveTo(leftOffset, rightOffset);
|
|
1178
1023
|
},
|
|
1179
1024
|
},
|
|
1180
1025
|
{
|
|
@@ -1186,6 +1031,35 @@ function stateModelFactory(pluginManager) {
|
|
|
1186
1031
|
},
|
|
1187
1032
|
];
|
|
1188
1033
|
},
|
|
1034
|
+
bpToPx: function (_a) {
|
|
1035
|
+
var refName = _a.refName, coord = _a.coord, regionNumber = _a.regionNumber;
|
|
1036
|
+
return (0, Base1DUtils_1.bpToPx)({ refName: refName, coord: coord, regionNumber: regionNumber, self: self });
|
|
1037
|
+
},
|
|
1038
|
+
/**
|
|
1039
|
+
* scrolls the view to center on the given bp. if that is not in any
|
|
1040
|
+
* of the displayed regions, does nothing
|
|
1041
|
+
* @param coord - basepair at which you want to center the view
|
|
1042
|
+
* @param refName - refName of the displayedRegion you are centering at
|
|
1043
|
+
* @param regionNumber - index of the displayedRegion
|
|
1044
|
+
*/
|
|
1045
|
+
centerAt: function (coord, refName, regionNumber) {
|
|
1046
|
+
var centerPx = this.bpToPx({
|
|
1047
|
+
refName: refName,
|
|
1048
|
+
coord: coord,
|
|
1049
|
+
regionNumber: regionNumber,
|
|
1050
|
+
});
|
|
1051
|
+
if (centerPx) {
|
|
1052
|
+
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
pxToBp: function (px) {
|
|
1056
|
+
return (0, Base1DUtils_1.pxToBp)(self, px);
|
|
1057
|
+
},
|
|
1058
|
+
get centerLineInfo() {
|
|
1059
|
+
return self.displayedRegions.length
|
|
1060
|
+
? this.pxToBp(self.width / 2)
|
|
1061
|
+
: undefined;
|
|
1062
|
+
},
|
|
1189
1063
|
}); });
|
|
1190
1064
|
}
|
|
1191
1065
|
exports.stateModelFactory = stateModelFactory;
|