igv 2.11.1 → 2.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -23
- package/dist/igv.esm.js +601 -624
- package/dist/igv.esm.min.js +9 -9
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +582 -633
- package/dist/igv.min.js +6 -6
- package/dist/igv.min.js.map +1 -1
- package/package.json +4 -4
package/dist/igv.js
CHANGED
|
@@ -17943,7 +17943,7 @@
|
|
|
17943
17943
|
* @constructor
|
|
17944
17944
|
*/
|
|
17945
17945
|
|
|
17946
|
-
class FeatureCache
|
|
17946
|
+
class FeatureCache {
|
|
17947
17947
|
constructor(featureList, genome, range) {
|
|
17948
17948
|
featureList = featureList || [];
|
|
17949
17949
|
this.treeMap = this.buildTreeMap(featureList, genome);
|
|
@@ -20733,13 +20733,14 @@
|
|
|
20733
20733
|
console.log('Viewport - draw(drawConfiguration, features, roiFeatures)');
|
|
20734
20734
|
}
|
|
20735
20735
|
|
|
20736
|
-
checkContentHeight(
|
|
20736
|
+
checkContentHeight() {
|
|
20737
20737
|
let track = this.trackView.track;
|
|
20738
|
-
features = features || this.cachedFeatures;
|
|
20739
20738
|
|
|
20740
20739
|
if ("FILL" === track.displayMode) {
|
|
20741
20740
|
this.setContentHeight(this.$viewport.height());
|
|
20742
20741
|
} else if (typeof track.computePixelHeight === 'function') {
|
|
20742
|
+
let features = this.cachedFeatures;
|
|
20743
|
+
|
|
20743
20744
|
if (features && features.length > 0) {
|
|
20744
20745
|
let requiredContentHeight = track.computePixelHeight(features);
|
|
20745
20746
|
let currentContentHeight = this.$content.height();
|
|
@@ -20759,7 +20760,7 @@
|
|
|
20759
20760
|
// Maximum height of a canvas is ~32,000 pixels on Chrome, possibly smaller on other platforms
|
|
20760
20761
|
contentHeight = Math.min(contentHeight, 32000);
|
|
20761
20762
|
this.$content.height(contentHeight);
|
|
20762
|
-
if (this.
|
|
20763
|
+
if (this.tile) this.tile.invalidate = true;
|
|
20763
20764
|
}
|
|
20764
20765
|
|
|
20765
20766
|
isLoading() {
|
|
@@ -20774,6 +20775,8 @@
|
|
|
20774
20775
|
|
|
20775
20776
|
setWidth(width) {
|
|
20776
20777
|
this.$viewport.width(width);
|
|
20778
|
+
this.canvas.style.width = `${width}px`;
|
|
20779
|
+
this.canvas.setAttribute('width', width);
|
|
20777
20780
|
}
|
|
20778
20781
|
|
|
20779
20782
|
getWidth() {
|
|
@@ -23058,7 +23061,7 @@
|
|
|
23058
23061
|
}
|
|
23059
23062
|
};
|
|
23060
23063
|
|
|
23061
|
-
const _version = "2.11.
|
|
23064
|
+
const _version = "2.11.2";
|
|
23062
23065
|
|
|
23063
23066
|
function version$1() {
|
|
23064
23067
|
return _version;
|
|
@@ -23575,20 +23578,16 @@
|
|
|
23575
23578
|
|
|
23576
23579
|
checkZoomIn() {
|
|
23577
23580
|
const showZoomInNotice = () => {
|
|
23581
|
+
const referenceFrame = this.referenceFrame;
|
|
23582
|
+
|
|
23578
23583
|
if (this.referenceFrame.chr.toLowerCase() === "all" && !this.trackView.track.supportsWholeGenome()) {
|
|
23579
23584
|
return true;
|
|
23580
23585
|
} else {
|
|
23581
23586
|
const visibilityWindow = this.trackView.track.visibilityWindow;
|
|
23582
|
-
return visibilityWindow !== undefined && visibilityWindow > 0 &&
|
|
23587
|
+
return visibilityWindow !== undefined && visibilityWindow > 0 && referenceFrame.bpPerPixel * this.$viewport.width() > visibilityWindow;
|
|
23583
23588
|
}
|
|
23584
23589
|
};
|
|
23585
23590
|
|
|
23586
|
-
if (this.trackView.track && "sequence" === this.trackView.track.type && this.referenceFrame.bpPerPixel > 1) {
|
|
23587
|
-
if (this.canvas) ;
|
|
23588
|
-
|
|
23589
|
-
return false;
|
|
23590
|
-
}
|
|
23591
|
-
|
|
23592
23591
|
if (!this.viewIsReady()) {
|
|
23593
23592
|
return false;
|
|
23594
23593
|
}
|
|
@@ -23598,8 +23597,7 @@
|
|
|
23598
23597
|
// Out of visibility window
|
|
23599
23598
|
if (this.canvas) {
|
|
23600
23599
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
23601
|
-
this.
|
|
23602
|
-
this.featureCache = undefined;
|
|
23600
|
+
this.tile = undefined;
|
|
23603
23601
|
}
|
|
23604
23602
|
|
|
23605
23603
|
this.$zoomInNotice.show();
|
|
@@ -23618,17 +23616,14 @@
|
|
|
23618
23616
|
|
|
23619
23617
|
return true;
|
|
23620
23618
|
}
|
|
23621
|
-
/**
|
|
23622
|
-
* Adjust the canvas to the current genomic state.
|
|
23623
|
-
*/
|
|
23624
|
-
|
|
23625
23619
|
|
|
23626
23620
|
shift() {
|
|
23627
|
-
const
|
|
23621
|
+
const self = this;
|
|
23622
|
+
const referenceFrame = self.referenceFrame;
|
|
23628
23623
|
|
|
23629
|
-
if (
|
|
23630
|
-
const pixelOffset = Math.round((
|
|
23631
|
-
|
|
23624
|
+
if (self.canvas && self.tile && self.tile.chr === self.referenceFrame.chr && self.tile.bpPerPixel === referenceFrame.bpPerPixel) {
|
|
23625
|
+
const pixelOffset = Math.round((self.tile.startBP - referenceFrame.start) / referenceFrame.bpPerPixel);
|
|
23626
|
+
self.canvas.style.left = pixelOffset + "px";
|
|
23632
23627
|
}
|
|
23633
23628
|
}
|
|
23634
23629
|
|
|
@@ -23654,10 +23649,9 @@
|
|
|
23654
23649
|
this.startSpinner();
|
|
23655
23650
|
|
|
23656
23651
|
try {
|
|
23657
|
-
const
|
|
23658
|
-
const features = await this.getFeatures(track, chr, bpStart, bpEnd, referenceFrame.bpPerPixel);
|
|
23652
|
+
const features = await this.getFeatures(this.trackView.track, chr, bpStart, bpEnd, referenceFrame.bpPerPixel);
|
|
23659
23653
|
let roiFeatures = [];
|
|
23660
|
-
const roi = mergeArrays(this.browser.roi, track.roi);
|
|
23654
|
+
const roi = mergeArrays(this.browser.roi, this.trackView.track.roi);
|
|
23661
23655
|
|
|
23662
23656
|
if (roi) {
|
|
23663
23657
|
for (let r of roi) {
|
|
@@ -23669,13 +23663,11 @@
|
|
|
23669
23663
|
}
|
|
23670
23664
|
}
|
|
23671
23665
|
|
|
23672
|
-
|
|
23673
|
-
|
|
23674
|
-
this.featureCache = new FeatureCache(chr, bpStart, bpEnd, referenceFrame.bpPerPixel, features, roiFeatures, mr);
|
|
23666
|
+
this.tile = new Tile(chr, bpStart, bpEnd, referenceFrame.bpPerPixel, features, roiFeatures);
|
|
23675
23667
|
this.loading = false;
|
|
23676
23668
|
this.hideMessage();
|
|
23677
23669
|
this.stopSpinner();
|
|
23678
|
-
return this.
|
|
23670
|
+
return this.tile;
|
|
23679
23671
|
} catch (error) {
|
|
23680
23672
|
// Track might have been removed during load
|
|
23681
23673
|
if (this.trackView && this.trackView.disposed !== true) {
|
|
@@ -23688,34 +23680,30 @@
|
|
|
23688
23680
|
this.stopSpinner();
|
|
23689
23681
|
}
|
|
23690
23682
|
}
|
|
23691
|
-
/**
|
|
23692
|
-
* Repaint the canvas for the current genomic state.
|
|
23693
|
-
*
|
|
23694
|
-
* @returns {Promise<void>}
|
|
23695
|
-
*/
|
|
23696
23683
|
|
|
23697
|
-
|
|
23698
|
-
|
|
23699
|
-
if (undefined === this.featureCache) {
|
|
23684
|
+
async repaint() {
|
|
23685
|
+
if (undefined === this.tile) {
|
|
23700
23686
|
return;
|
|
23701
23687
|
}
|
|
23702
23688
|
|
|
23703
23689
|
let {
|
|
23704
23690
|
features,
|
|
23705
|
-
roiFeatures
|
|
23706
|
-
|
|
23707
|
-
|
|
23691
|
+
roiFeatures,
|
|
23692
|
+
bpPerPixel,
|
|
23693
|
+
startBP,
|
|
23694
|
+
endBP
|
|
23695
|
+
} = this.tile; // const isWGV = GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr)
|
|
23708
23696
|
|
|
23709
23697
|
const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
|
|
23710
23698
|
let pixelWidth;
|
|
23711
|
-
const startBP = this.featureCache.startBP;
|
|
23712
|
-
const endBP = this.featureCache.endBP;
|
|
23713
|
-
let bpPerPixel = this.referenceFrame.bpPerPixel;
|
|
23714
23699
|
|
|
23715
23700
|
if (isWGV) {
|
|
23701
|
+
bpPerPixel = this.referenceFrame.end / this.$viewport.width();
|
|
23702
|
+
startBP = 0;
|
|
23703
|
+
endBP = this.referenceFrame.end;
|
|
23716
23704
|
pixelWidth = this.$viewport.width();
|
|
23717
23705
|
} else {
|
|
23718
|
-
pixelWidth =
|
|
23706
|
+
pixelWidth = Math.ceil((endBP - startBP) / bpPerPixel);
|
|
23719
23707
|
} // For deep tracks we paint a canvas == 3*viewportHeight centered on the current vertical scroll position
|
|
23720
23708
|
|
|
23721
23709
|
|
|
@@ -23768,33 +23756,21 @@
|
|
|
23768
23756
|
viewport: this,
|
|
23769
23757
|
viewportWidth: this.$viewport.width()
|
|
23770
23758
|
};
|
|
23771
|
-
this.draw(drawConfiguration, features, roiFeatures);
|
|
23772
|
-
|
|
23773
|
-
newCanvas._data = {
|
|
23774
|
-
chr: this.referenceFrame.chr,
|
|
23775
|
-
startBP,
|
|
23776
|
-
endBP,
|
|
23777
|
-
bpPerPixel,
|
|
23759
|
+
this.draw(drawConfiguration, features, roiFeatures);
|
|
23760
|
+
this.canvasVerticalRange = {
|
|
23778
23761
|
top: canvasTop,
|
|
23779
23762
|
bottom: canvasTop + pixelHeight
|
|
23780
23763
|
};
|
|
23781
23764
|
|
|
23782
|
-
if (this
|
|
23783
|
-
|
|
23765
|
+
if (this.$canvas) {
|
|
23766
|
+
this.$canvas.remove();
|
|
23784
23767
|
}
|
|
23785
23768
|
|
|
23769
|
+
this.$canvas = $$1(newCanvas);
|
|
23770
|
+
this.$content.append(this.$canvas);
|
|
23786
23771
|
this.canvas = newCanvas;
|
|
23787
23772
|
this.ctx = ctx;
|
|
23788
|
-
this.$content.append($$1(newCanvas));
|
|
23789
23773
|
}
|
|
23790
|
-
/**
|
|
23791
|
-
* Draw the associated track.
|
|
23792
|
-
*
|
|
23793
|
-
* @param drawConfiguration
|
|
23794
|
-
* @param features
|
|
23795
|
-
* @param roiFeatures
|
|
23796
|
-
*/
|
|
23797
|
-
|
|
23798
23774
|
|
|
23799
23775
|
draw(drawConfiguration, features, roiFeatures) {
|
|
23800
23776
|
// console.log(`${ Date.now() } viewport draw(). track ${ this.trackView.track.type }. content-css-top ${ this.$content.css('top') }. canvas-top ${ drawConfiguration.pixelTop }.`)
|
|
@@ -23809,6 +23785,51 @@
|
|
|
23809
23785
|
r.track.draw(drawConfiguration);
|
|
23810
23786
|
}
|
|
23811
23787
|
}
|
|
23788
|
+
} // TODO: Nolonger used. Will discard
|
|
23789
|
+
|
|
23790
|
+
|
|
23791
|
+
async toSVG(tile) {
|
|
23792
|
+
// Nothing to do if zoomInNotice is active
|
|
23793
|
+
if (this.$zoomInNotice && this.$zoomInNotice.is(":visible")) {
|
|
23794
|
+
return;
|
|
23795
|
+
}
|
|
23796
|
+
|
|
23797
|
+
const referenceFrame = this.referenceFrame;
|
|
23798
|
+
const bpPerPixel = tile.bpPerPixel;
|
|
23799
|
+
const features = tile.features;
|
|
23800
|
+
const roiFeatures = tile.roiFeatures;
|
|
23801
|
+
const pixelWidth = this.$viewport.width();
|
|
23802
|
+
const pixelHeight = this.$viewport.height();
|
|
23803
|
+
const bpStart = referenceFrame.start;
|
|
23804
|
+
const bpEnd = referenceFrame.start + pixelWidth * referenceFrame.bpPerPixel;
|
|
23805
|
+
const ctx$1 = new ctx({
|
|
23806
|
+
// svg
|
|
23807
|
+
width: pixelWidth,
|
|
23808
|
+
height: pixelHeight,
|
|
23809
|
+
viewbox: {
|
|
23810
|
+
x: 0,
|
|
23811
|
+
y: -this.$content.position().top,
|
|
23812
|
+
width: pixelWidth,
|
|
23813
|
+
height: pixelHeight
|
|
23814
|
+
}
|
|
23815
|
+
});
|
|
23816
|
+
const drawConfiguration = {
|
|
23817
|
+
viewport: this,
|
|
23818
|
+
context: ctx$1,
|
|
23819
|
+
top: -this.$content.position().top,
|
|
23820
|
+
pixelTop: 0,
|
|
23821
|
+
// for compatibility with canvas draw
|
|
23822
|
+
pixelWidth,
|
|
23823
|
+
pixelHeight,
|
|
23824
|
+
bpStart,
|
|
23825
|
+
bpEnd,
|
|
23826
|
+
bpPerPixel,
|
|
23827
|
+
referenceFrame: this.referenceFrame,
|
|
23828
|
+
selection: this.selection,
|
|
23829
|
+
viewportWidth: pixelWidth
|
|
23830
|
+
};
|
|
23831
|
+
this.draw(drawConfiguration, features, roiFeatures);
|
|
23832
|
+
return ctx$1.getSerializedSvg(true);
|
|
23812
23833
|
}
|
|
23813
23834
|
|
|
23814
23835
|
containsPosition(chr, position) {
|
|
@@ -23823,10 +23844,9 @@
|
|
|
23823
23844
|
return this.loading;
|
|
23824
23845
|
}
|
|
23825
23846
|
|
|
23826
|
-
|
|
23847
|
+
saveImage() {
|
|
23827
23848
|
if (!this.ctx) return;
|
|
23828
|
-
const
|
|
23829
|
-
const canvasTop = canvasMetadata ? canvasMetadata.top : 0;
|
|
23849
|
+
const canvasTop = this.canvasVerticalRange ? this.canvasVerticalRange.top : 0;
|
|
23830
23850
|
const devicePixelRatio = window.devicePixelRatio;
|
|
23831
23851
|
const w = this.$viewport.width() * devicePixelRatio;
|
|
23832
23852
|
const h = this.$viewport.height() * devicePixelRatio;
|
|
@@ -23948,22 +23968,23 @@
|
|
|
23948
23968
|
viewportWidth: width,
|
|
23949
23969
|
selection: this.selection
|
|
23950
23970
|
};
|
|
23951
|
-
const features = this.
|
|
23952
|
-
const roiFeatures = this.
|
|
23971
|
+
const features = this.tile ? this.tile.features : [];
|
|
23972
|
+
const roiFeatures = this.tile ? this.tile.roiFeatures : undefined;
|
|
23953
23973
|
this.draw(config, features, roiFeatures);
|
|
23954
23974
|
context.restore();
|
|
23955
23975
|
}
|
|
23956
23976
|
|
|
23957
|
-
|
|
23958
|
-
return this.
|
|
23977
|
+
getCachedFeatures() {
|
|
23978
|
+
return this.tile ? this.tile.features : [];
|
|
23959
23979
|
}
|
|
23960
23980
|
|
|
23961
23981
|
async getFeatures(track, chr, start, end, bpPerPixel) {
|
|
23962
|
-
if (this.
|
|
23963
|
-
return this.
|
|
23982
|
+
if (this.tile && this.tile.containsRange(chr, start, end, bpPerPixel)) {
|
|
23983
|
+
return this.tile.features;
|
|
23964
23984
|
} else if (typeof track.getFeatures === "function") {
|
|
23965
23985
|
const features = await track.getFeatures(chr, start, end, bpPerPixel, this);
|
|
23966
|
-
this.
|
|
23986
|
+
this.cachedFeatures = features;
|
|
23987
|
+
this.checkContentHeight();
|
|
23967
23988
|
return features;
|
|
23968
23989
|
} else {
|
|
23969
23990
|
return undefined;
|
|
@@ -24243,6 +24264,11 @@
|
|
|
24243
24264
|
const viewportCoords = translateMouseCoordinates$1(event, viewport.contentDiv);
|
|
24244
24265
|
const canvasCoords = translateMouseCoordinates$1(event, viewport.canvas);
|
|
24245
24266
|
const genomicLocation = referenceFrame.start + referenceFrame.toBP(viewportCoords.x);
|
|
24267
|
+
|
|
24268
|
+
if (undefined === genomicLocation || null === viewport.tile) {
|
|
24269
|
+
return undefined;
|
|
24270
|
+
}
|
|
24271
|
+
|
|
24246
24272
|
return {
|
|
24247
24273
|
event,
|
|
24248
24274
|
viewport,
|
|
@@ -24296,28 +24322,22 @@
|
|
|
24296
24322
|
return rows.join('');
|
|
24297
24323
|
}
|
|
24298
24324
|
|
|
24299
|
-
|
|
24300
|
-
|
|
24301
|
-
|
|
24302
|
-
|
|
24303
|
-
|
|
24304
|
-
|
|
24305
|
-
|
|
24306
|
-
|
|
24307
|
-
this.multiresolution = multiresolution;
|
|
24308
|
-
}
|
|
24309
|
-
|
|
24310
|
-
containsRange(chr, start, end, bpPerPixel) {
|
|
24311
|
-
// For multi-resolution tracks allow for a 2X change in bpPerPixel
|
|
24312
|
-
const r = this.multiresolution ? this.bpPerPixel / bpPerPixel : 1;
|
|
24313
|
-
return start >= this.startBP && end <= this.endBP && chr === this.chr && r > 0.5 && r < 2;
|
|
24314
|
-
}
|
|
24325
|
+
var Tile = function (chr, tileStart, tileEnd, bpPerPixel, features, roiFeatures) {
|
|
24326
|
+
this.chr = chr;
|
|
24327
|
+
this.startBP = tileStart;
|
|
24328
|
+
this.endBP = tileEnd;
|
|
24329
|
+
this.bpPerPixel = bpPerPixel;
|
|
24330
|
+
this.features = features;
|
|
24331
|
+
this.roiFeatures = roiFeatures;
|
|
24332
|
+
};
|
|
24315
24333
|
|
|
24316
|
-
|
|
24317
|
-
|
|
24318
|
-
|
|
24334
|
+
Tile.prototype.containsRange = function (chr, start, end, bpPerPixel) {
|
|
24335
|
+
return this.bpPerPixel === bpPerPixel && start >= this.startBP && end <= this.endBP && chr === this.chr;
|
|
24336
|
+
};
|
|
24319
24337
|
|
|
24320
|
-
|
|
24338
|
+
Tile.prototype.overlapsRange = function (chr, start, end) {
|
|
24339
|
+
return this.chr === chr && end >= this.startBP && start <= this.endBP;
|
|
24340
|
+
};
|
|
24321
24341
|
/**
|
|
24322
24342
|
* Merge 2 arrays. a and/or b can be undefined. If both are undefined, return undefined
|
|
24323
24343
|
* @param a An array or undefined
|
|
@@ -25461,18 +25481,6 @@
|
|
|
25461
25481
|
return true; // By definition
|
|
25462
25482
|
}
|
|
25463
25483
|
|
|
25464
|
-
isMateMapped() {
|
|
25465
|
-
return true; // By definition
|
|
25466
|
-
}
|
|
25467
|
-
|
|
25468
|
-
isProperPair() {
|
|
25469
|
-
return this.firstAlignment.isProperPair();
|
|
25470
|
-
}
|
|
25471
|
-
|
|
25472
|
-
get tlen() {
|
|
25473
|
-
return Math.abs(this.firstAlignment.fragmentLength);
|
|
25474
|
-
}
|
|
25475
|
-
|
|
25476
25484
|
firstOfPairStrand() {
|
|
25477
25485
|
if (this.firstAlignment.isFirstOfPair()) {
|
|
25478
25486
|
return this.firstAlignment.strand;
|
|
@@ -25839,15 +25847,7 @@
|
|
|
25839
25847
|
*/
|
|
25840
25848
|
|
|
25841
25849
|
class AlignmentContainer {
|
|
25842
|
-
|
|
25843
|
-
// this.config.pairsSupported, this.config.alleleFreqThreshold)
|
|
25844
|
-
constructor(chr, start, end, _ref) {
|
|
25845
|
-
let {
|
|
25846
|
-
samplingWindowSize,
|
|
25847
|
-
samplingDepth,
|
|
25848
|
-
pairsSupported,
|
|
25849
|
-
alleleFreqThreshold
|
|
25850
|
-
} = _ref;
|
|
25850
|
+
constructor(chr, start, end, samplingWindowSize, samplingDepth, pairsSupported, alleleFreqThreshold) {
|
|
25851
25851
|
this.chr = chr;
|
|
25852
25852
|
this.start = Math.floor(start);
|
|
25853
25853
|
this.end = Math.ceil(end);
|
|
@@ -25870,10 +25870,17 @@
|
|
|
25870
25870
|
// TODO -- pass this in
|
|
25871
25871
|
return alignment.isMapped() && !alignment.isFailsVendorQualityCheck();
|
|
25872
25872
|
};
|
|
25873
|
+
|
|
25874
|
+
this.pairedEndStats = new PairedEndStats();
|
|
25873
25875
|
}
|
|
25874
25876
|
|
|
25875
25877
|
push(alignment) {
|
|
25876
25878
|
if (this.filter(alignment) === false) return;
|
|
25879
|
+
|
|
25880
|
+
if (alignment.isPaired()) {
|
|
25881
|
+
this.pairedEndStats.push(alignment);
|
|
25882
|
+
}
|
|
25883
|
+
|
|
25877
25884
|
this.coverageMap.incCounts(alignment); // Count coverage before any downsampling
|
|
25878
25885
|
|
|
25879
25886
|
if (this.pairsSupported && this.downsampledReads.has(alignment.readName)) {
|
|
@@ -25902,6 +25909,7 @@
|
|
|
25902
25909
|
});
|
|
25903
25910
|
this.pairsCache = undefined;
|
|
25904
25911
|
this.downsampledReads = undefined;
|
|
25912
|
+
this.pairedEndStats.compute();
|
|
25905
25913
|
}
|
|
25906
25914
|
|
|
25907
25915
|
contains(chr, start, end) {
|
|
@@ -26196,6 +26204,62 @@
|
|
|
26196
26204
|
|
|
26197
26205
|
}
|
|
26198
26206
|
|
|
26207
|
+
class PairedEndStats {
|
|
26208
|
+
constructor(lowerPercentile, upperPercentile) {
|
|
26209
|
+
this.totalCount = 0;
|
|
26210
|
+
this.frCount = 0;
|
|
26211
|
+
this.rfCount = 0;
|
|
26212
|
+
this.ffCount = 0;
|
|
26213
|
+
this.sumF = 0;
|
|
26214
|
+
this.sumF2 = 0; //this.lp = lowerPercentile === undefined ? 0.005 : lowerPercentile;
|
|
26215
|
+
//this.up = upperPercentile === undefined ? 0.995 : upperPercentile;
|
|
26216
|
+
//this.digest = new Digest();
|
|
26217
|
+
}
|
|
26218
|
+
|
|
26219
|
+
push(alignment) {
|
|
26220
|
+
if (alignment.isProperPair()) {
|
|
26221
|
+
var fragmentLength = Math.abs(alignment.fragmentLength); //this.digest.push(fragmentLength);
|
|
26222
|
+
|
|
26223
|
+
this.sumF += fragmentLength;
|
|
26224
|
+
this.sumF2 += fragmentLength * fragmentLength;
|
|
26225
|
+
var po = alignment.pairOrientation;
|
|
26226
|
+
|
|
26227
|
+
if (typeof po === "string" && po.length === 4) {
|
|
26228
|
+
var tmp = '' + po.charAt(0) + po.charAt(2);
|
|
26229
|
+
|
|
26230
|
+
switch (tmp) {
|
|
26231
|
+
case 'FF':
|
|
26232
|
+
case 'RR':
|
|
26233
|
+
this.ffCount++;
|
|
26234
|
+
break;
|
|
26235
|
+
|
|
26236
|
+
case "FR":
|
|
26237
|
+
this.frCount++;
|
|
26238
|
+
break;
|
|
26239
|
+
|
|
26240
|
+
case "RF":
|
|
26241
|
+
this.rfCount++;
|
|
26242
|
+
}
|
|
26243
|
+
}
|
|
26244
|
+
|
|
26245
|
+
this.totalCount++;
|
|
26246
|
+
}
|
|
26247
|
+
}
|
|
26248
|
+
|
|
26249
|
+
compute() {
|
|
26250
|
+
if (this.totalCount > 100) {
|
|
26251
|
+
if (this.ffCount / this.totalCount > 0.9) this.orienation = "ff";else if (this.frCount / this.totalCount > 0.9) this.orienation = "fr";else if (this.rfCount / this.totalCount > 0.9) this.orienation = "rf";
|
|
26252
|
+
var fMean = this.sumF / this.totalCount;
|
|
26253
|
+
var stdDev = Math.sqrt((this.totalCount * this.sumF2 - this.sumF * this.sumF) / (this.totalCount * this.totalCount));
|
|
26254
|
+
this.lowerFragmentLength = fMean - 3 * stdDev;
|
|
26255
|
+
this.upperFragmentLength = fMean + 3 * stdDev; //this.lowerFragmentLength = this.digest.percentile(this.lp);
|
|
26256
|
+
//this.upperFragmentLength = this.digest.percentile(this.up);
|
|
26257
|
+
//this.digest = undefined;
|
|
26258
|
+
}
|
|
26259
|
+
}
|
|
26260
|
+
|
|
26261
|
+
}
|
|
26262
|
+
|
|
26199
26263
|
class SupplementaryAlignment {
|
|
26200
26264
|
constructor(rec) {
|
|
26201
26265
|
const tokens = rec.split(',');
|
|
@@ -27399,7 +27463,7 @@
|
|
|
27399
27463
|
const header = this.header;
|
|
27400
27464
|
const queryChr = header.chrAliasTable.hasOwnProperty(chr) ? header.chrAliasTable[chr] : chr;
|
|
27401
27465
|
const qAlignments = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd);
|
|
27402
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
27466
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.samplingWindowSize, this.samplingDepth, this.pairsSupported, this.alleleFreqThreshold);
|
|
27403
27467
|
|
|
27404
27468
|
for (let a of qAlignments) {
|
|
27405
27469
|
alignmentContainer.push(a);
|
|
@@ -27426,13 +27490,13 @@
|
|
|
27426
27490
|
const alignments = [];
|
|
27427
27491
|
this.header = BamUtils.decodeBamHeader(data);
|
|
27428
27492
|
BamUtils.decodeBamRecords(data, this.header.size, alignments, this.header.chrNames);
|
|
27429
|
-
this.alignmentCache = new FeatureCache
|
|
27493
|
+
this.alignmentCache = new FeatureCache(alignments, this.genome);
|
|
27430
27494
|
}
|
|
27431
27495
|
|
|
27432
27496
|
fetchAlignments(chr, bpStart, bpEnd) {
|
|
27433
27497
|
const queryChr = this.header.chrAliasTable.hasOwnProperty(chr) ? this.header.chrAliasTable[chr] : chr;
|
|
27434
27498
|
const features = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd);
|
|
27435
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
27499
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.samplingWindowSize, this.samplingDepth, this.pairsSupported);
|
|
27436
27500
|
|
|
27437
27501
|
for (let feature of features) {
|
|
27438
27502
|
alignmentContainer.push(feature);
|
|
@@ -28432,7 +28496,7 @@
|
|
|
28432
28496
|
const chrToIndex = await this.getChrIndex();
|
|
28433
28497
|
const queryChr = this.chrAliasTable.hasOwnProperty(chr) ? this.chrAliasTable[chr] : chr;
|
|
28434
28498
|
const chrId = chrToIndex[queryChr];
|
|
28435
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config);
|
|
28499
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config.samplingWindowSize, this.config.samplingDepth, this.config.pairsSupported, this.config.alleleFreqThreshold);
|
|
28436
28500
|
|
|
28437
28501
|
if (chrId === undefined) {
|
|
28438
28502
|
return alignmentContainer;
|
|
@@ -28581,7 +28645,7 @@
|
|
|
28581
28645
|
|
|
28582
28646
|
async readAlignments(chr, start, end) {
|
|
28583
28647
|
if (!this.bamReaders.hasOwnProperty(chr)) {
|
|
28584
|
-
return new AlignmentContainer(chr, start, end
|
|
28648
|
+
return new AlignmentContainer(chr, start, end);
|
|
28585
28649
|
} else {
|
|
28586
28650
|
let reader = this.bamReaders[chr];
|
|
28587
28651
|
const a = await reader.readAlignments(chr, start, end);
|
|
@@ -28653,7 +28717,7 @@
|
|
|
28653
28717
|
return igvxhr.loadString(url, buildOptions(self.config)).then(function (sam) {
|
|
28654
28718
|
var alignmentContainer;
|
|
28655
28719
|
header.chrToIndex[queryChr];
|
|
28656
|
-
alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, self.
|
|
28720
|
+
alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, self.samplingWindowSize, self.samplingDepth, self.pairsSupported, self.alleleFreqThreshold);
|
|
28657
28721
|
BamUtils.decodeSamRecords(sam, alignmentContainer, queryChr, bpStart, bpEnd, self.filter);
|
|
28658
28722
|
return alignmentContainer;
|
|
28659
28723
|
});
|
|
@@ -28863,7 +28927,7 @@
|
|
|
28863
28927
|
|
|
28864
28928
|
const ba = unbgzf(compressedData.buffer);
|
|
28865
28929
|
const chrIdx = this.header.chrToIndex[chr];
|
|
28866
|
-
const alignmentContainer = new AlignmentContainer(chr, start, end, this.
|
|
28930
|
+
const alignmentContainer = new AlignmentContainer(chr, start, end, this.samplingWindowSize, this.samplingDepth, this.pairsSupported, this.alleleFreqThreshold);
|
|
28867
28931
|
BamUtils.decodeBamRecords(ba, this.header.size, alignmentContainer, this.header.chrNames, chrIdx, start, end);
|
|
28868
28932
|
alignmentContainer.finish();
|
|
28869
28933
|
return alignmentContainer;
|
|
@@ -44401,7 +44465,7 @@
|
|
|
44401
44465
|
const header = await this.getHeader();
|
|
44402
44466
|
const queryChr = header.chrAliasTable.hasOwnProperty(chr) ? header.chrAliasTable[chr] : chr;
|
|
44403
44467
|
const chrIdx = header.chrToIndex[queryChr];
|
|
44404
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
44468
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.samplingWindowSize, this.samplingDepth, this.pairsSupported, this.alleleFreqThreshold);
|
|
44405
44469
|
|
|
44406
44470
|
if (chrIdx === undefined) {
|
|
44407
44471
|
return alignmentContainer;
|
|
@@ -45010,7 +45074,7 @@
|
|
|
45010
45074
|
"pageSize": "10000"
|
|
45011
45075
|
},
|
|
45012
45076
|
decode: decodeGa4ghReads,
|
|
45013
|
-
results: new AlignmentContainer(chr, bpStart, bpEnd, self.
|
|
45077
|
+
results: new AlignmentContainer(chr, bpStart, bpEnd, self.samplingWindowSize, self.samplingDepth, self.pairsSupported, self.alleleFreqThreshold)
|
|
45014
45078
|
});
|
|
45015
45079
|
});
|
|
45016
45080
|
|
|
@@ -45317,6 +45381,7 @@
|
|
|
45317
45381
|
const genome = browser.genome;
|
|
45318
45382
|
this.config = config;
|
|
45319
45383
|
this.genome = genome;
|
|
45384
|
+
this.alignmentContainer = undefined;
|
|
45320
45385
|
|
|
45321
45386
|
if (isDataURL(config.url)) {
|
|
45322
45387
|
if ("cram" === config.format) {
|
|
@@ -45367,44 +45432,58 @@
|
|
|
45367
45432
|
}
|
|
45368
45433
|
|
|
45369
45434
|
setViewAsPairs(bool) {
|
|
45370
|
-
|
|
45435
|
+
|
|
45436
|
+
if (this.viewAsPairs !== bool) {
|
|
45437
|
+
this.viewAsPairs = bool; // if (this.alignmentContainer) {
|
|
45438
|
+
// this.alignmentContainer.setViewAsPairs(bool);
|
|
45439
|
+
// }
|
|
45440
|
+
}
|
|
45371
45441
|
}
|
|
45372
45442
|
|
|
45373
45443
|
setShowSoftClips(bool) {
|
|
45374
|
-
this.showSoftClips
|
|
45444
|
+
if (this.showSoftClips !== bool) {
|
|
45445
|
+
this.showSoftClips = bool;
|
|
45446
|
+
}
|
|
45375
45447
|
}
|
|
45376
45448
|
|
|
45377
45449
|
async getAlignments(chr, bpStart, bpEnd) {
|
|
45378
45450
|
const genome = this.genome;
|
|
45379
45451
|
const showSoftClips = this.showSoftClips;
|
|
45380
|
-
const alignmentContainer = await this.bamReader.readAlignments(chr, bpStart, bpEnd);
|
|
45381
|
-
let alignments = alignmentContainer.alignments;
|
|
45382
45452
|
|
|
45383
|
-
if (
|
|
45384
|
-
|
|
45385
|
-
|
|
45386
|
-
|
|
45387
|
-
|
|
45453
|
+
if (this.alignmentContainer && this.alignmentContainer.contains(chr, bpStart, bpEnd)) {
|
|
45454
|
+
return this.alignmentContainer;
|
|
45455
|
+
} else {
|
|
45456
|
+
const alignmentContainer = await this.bamReader.readAlignments(chr, bpStart, bpEnd);
|
|
45457
|
+
let alignments = alignmentContainer.alignments;
|
|
45388
45458
|
|
|
45389
|
-
|
|
45390
|
-
|
|
45391
|
-
|
|
45459
|
+
if (!this.viewAsPairs) {
|
|
45460
|
+
alignments = unpairAlignments([{
|
|
45461
|
+
alignments: alignments
|
|
45462
|
+
}]);
|
|
45463
|
+
}
|
|
45392
45464
|
|
|
45393
|
-
|
|
45394
|
-
|
|
45465
|
+
const hasAlignments = alignments.length > 0;
|
|
45466
|
+
alignmentContainer.packedAlignmentRows = packAlignmentRows(alignments, alignmentContainer.start, alignmentContainer.end, showSoftClips);
|
|
45467
|
+
alignmentContainer.alignments = undefined; // Don't need to hold onto these anymore
|
|
45395
45468
|
|
|
45396
|
-
|
|
45397
|
-
alignmentContainer.coverageMap.refSeq = sequence; // TODO -- fix this
|
|
45469
|
+
this.alignmentContainer = alignmentContainer;
|
|
45398
45470
|
|
|
45399
|
-
|
|
45471
|
+
if (hasAlignments) {
|
|
45472
|
+
const sequence = await genome.sequence.getSequence(chr, alignmentContainer.start, alignmentContainer.end);
|
|
45400
45473
|
|
|
45401
|
-
|
|
45402
|
-
|
|
45403
|
-
|
|
45474
|
+
if (sequence) {
|
|
45475
|
+
alignmentContainer.coverageMap.refSeq = sequence; // TODO -- fix this
|
|
45476
|
+
|
|
45477
|
+
alignmentContainer.sequence = sequence; // TODO -- fix this
|
|
45478
|
+
|
|
45479
|
+
return alignmentContainer;
|
|
45480
|
+
} else {
|
|
45481
|
+
console.error("No sequence for: " + chr + ":" + alignmentContainer.start + "-" + alignmentContainer.end);
|
|
45482
|
+
}
|
|
45404
45483
|
}
|
|
45405
|
-
}
|
|
45406
45484
|
|
|
45407
|
-
|
|
45485
|
+
return alignmentContainer;
|
|
45486
|
+
}
|
|
45408
45487
|
}
|
|
45409
45488
|
|
|
45410
45489
|
}
|
|
@@ -45749,7 +45828,7 @@
|
|
|
45749
45828
|
clickedFeatures(clickState, features) {
|
|
45750
45829
|
// We use the cached features rather than method to avoid async load. If the
|
|
45751
45830
|
// feature is not already loaded this won't work, but the user wouldn't be mousing over it either.
|
|
45752
|
-
if (!features) features = clickState.viewport.
|
|
45831
|
+
if (!features) features = clickState.viewport.getCachedFeatures();
|
|
45753
45832
|
|
|
45754
45833
|
if (!features || features.length === 0) {
|
|
45755
45834
|
return [];
|
|
@@ -48388,117 +48467,50 @@
|
|
|
48388
48467
|
return regions;
|
|
48389
48468
|
}
|
|
48390
48469
|
|
|
48391
|
-
function sendChords(chords, track, refFrame, alpha) {
|
|
48392
|
-
const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? track.color : getChrColor(refFrame.chr), alpha);
|
|
48393
|
-
const trackColor = IGVColor.addAlpha(track.color || 'rgb(0,0,255)', alpha); // name the chord set to include locus and filtering information
|
|
48394
|
-
|
|
48395
|
-
const encodedName = track.name.replaceAll(' ', '%20');
|
|
48396
|
-
const chordSetName = "all" === refFrame.chr ? encodedName : `${encodedName} ${refFrame.chr}:${refFrame.start}-${refFrame.end}`;
|
|
48397
|
-
track.browser.circularView.addChords(chords, {
|
|
48398
|
-
track: chordSetName,
|
|
48399
|
-
color: chordSetColor,
|
|
48400
|
-
trackColor: trackColor
|
|
48401
|
-
});
|
|
48402
|
-
}
|
|
48403
|
-
|
|
48404
48470
|
function createCircularView(el, browser) {
|
|
48405
48471
|
const circularView = new CircularView(el, {
|
|
48406
48472
|
onChordClick: (feature, chordTrack, pluginManager) => {
|
|
48407
48473
|
const f1 = feature.data;
|
|
48408
48474
|
const f2 = f1.mate;
|
|
48409
|
-
|
|
48410
|
-
|
|
48411
|
-
|
|
48412
|
-
|
|
48413
|
-
|
|
48414
|
-
|
|
48415
|
-
|
|
48416
|
-
|
|
48417
|
-
|
|
48418
|
-
|
|
48419
|
-
|
|
48420
|
-
|
|
48421
|
-
|
|
48422
|
-
|
|
48423
|
-
|
|
48424
|
-
|
|
48425
|
-
|
|
48426
|
-
|
|
48427
|
-
|
|
48475
|
+
const flanking = 2000;
|
|
48476
|
+
const l1 = new Locus({
|
|
48477
|
+
chr: browser.genome.getChromosomeName(f1.refName),
|
|
48478
|
+
start: f1.start,
|
|
48479
|
+
end: f1.end
|
|
48480
|
+
});
|
|
48481
|
+
const l2 = new Locus({
|
|
48482
|
+
chr: browser.genome.getChromosomeName(f2.refName),
|
|
48483
|
+
start: f2.start,
|
|
48484
|
+
end: f2.end
|
|
48485
|
+
});
|
|
48486
|
+
let loci; // If there is overlap with current loci
|
|
48487
|
+
|
|
48488
|
+
loci = browser.currentLoci().map(str => Locus.fromLocusString(str));
|
|
48489
|
+
|
|
48490
|
+
if (loci.some(locus => locus.contains(l1)) || loci.some(locus => locus.contains(l2))) {
|
|
48491
|
+
for (let l of [l1, l2]) {
|
|
48492
|
+
if (!loci.some(locus => {
|
|
48493
|
+
return locus.contains(l);
|
|
48494
|
+
})) {
|
|
48495
|
+
// add flanking
|
|
48496
|
+
l.start = Math.max(0, l.start - flanking);
|
|
48497
|
+
l.end += flanking;
|
|
48498
|
+
loci.push(l);
|
|
48428
48499
|
}
|
|
48429
48500
|
}
|
|
48501
|
+
} else {
|
|
48502
|
+
l1.start = Math.max(0, l1.start - flanking);
|
|
48503
|
+
l1.end += flanking;
|
|
48504
|
+
l2.start = Math.max(0, l2.start - flanking);
|
|
48505
|
+
l2.end += flanking;
|
|
48506
|
+
loci = [l1, l2];
|
|
48430
48507
|
}
|
|
48431
|
-
}
|
|
48432
|
-
});
|
|
48433
|
-
return circularView;
|
|
48434
|
-
}
|
|
48435
|
-
|
|
48436
|
-
class PairedEndStats {
|
|
48437
|
-
constructor(alignments, _ref) {
|
|
48438
|
-
let {
|
|
48439
|
-
minTLENPercentile,
|
|
48440
|
-
maxTLENPercentile
|
|
48441
|
-
} = _ref;
|
|
48442
|
-
this.totalCount = 0;
|
|
48443
|
-
this.frCount = 0;
|
|
48444
|
-
this.rfCount = 0;
|
|
48445
|
-
this.ffCount = 0;
|
|
48446
|
-
this.sumF = 0;
|
|
48447
|
-
this.sumF2 = 0;
|
|
48448
|
-
this.lp = minTLENPercentile === undefined ? 0.1 : minTLENPercentile;
|
|
48449
|
-
this.up = maxTLENPercentile === undefined ? 99.5 : maxTLENPercentile;
|
|
48450
|
-
this.isizes = [];
|
|
48451
|
-
this.compute(alignments);
|
|
48452
|
-
}
|
|
48453
|
-
|
|
48454
|
-
compute(alignments) {
|
|
48455
|
-
for (let alignment of alignments) {
|
|
48456
|
-
if (alignment.isProperPair()) {
|
|
48457
|
-
var tlen = Math.abs(alignment.fragmentLength);
|
|
48458
|
-
this.sumF += tlen;
|
|
48459
|
-
this.sumF2 += tlen * tlen;
|
|
48460
|
-
this.isizes.push(tlen);
|
|
48461
|
-
var po = alignment.pairOrientation;
|
|
48462
|
-
|
|
48463
|
-
if (typeof po === "string" && po.length === 4) {
|
|
48464
|
-
var tmp = '' + po.charAt(0) + po.charAt(2);
|
|
48465
|
-
|
|
48466
|
-
switch (tmp) {
|
|
48467
|
-
case 'FF':
|
|
48468
|
-
case 'RR':
|
|
48469
|
-
this.ffCount++;
|
|
48470
|
-
break;
|
|
48471
|
-
|
|
48472
|
-
case "FR":
|
|
48473
|
-
this.frCount++;
|
|
48474
|
-
break;
|
|
48475
48508
|
|
|
48476
|
-
|
|
48477
|
-
|
|
48478
|
-
}
|
|
48479
|
-
}
|
|
48480
|
-
|
|
48481
|
-
this.totalCount++;
|
|
48482
|
-
}
|
|
48509
|
+
const searchString = loci.map(l => l.getLocusString()).join(" ");
|
|
48510
|
+
browser.search(searchString);
|
|
48483
48511
|
}
|
|
48484
|
-
|
|
48485
|
-
if (this.ffCount / this.totalCount > 0.9) this.orienation = "ff";else if (this.frCount / this.totalCount > 0.9) this.orienation = "fr";else if (this.rfCount / this.totalCount > 0.9) this.orienation = "rf";
|
|
48486
|
-
this.minTLEN = this.lp === 0 ? 0 : percentile(this.isizes, this.lp);
|
|
48487
|
-
this.maxTLEN = percentile(this.isizes, this.up); // var fMean = this.sumF / this.totalCount
|
|
48488
|
-
// var stdDev = Math.sqrt((this.totalCount * this.sumF2 - this.sumF * this.sumF) / (this.totalCount * this.totalCount))
|
|
48489
|
-
// this.minTLEN = fMean - 3 * stdDev
|
|
48490
|
-
// this.maxTLEN = fMean + 3 * stdDev
|
|
48491
|
-
}
|
|
48492
|
-
|
|
48493
|
-
}
|
|
48494
|
-
|
|
48495
|
-
function percentile(array, p) {
|
|
48496
|
-
if (array.length === 0) return undefined;
|
|
48497
|
-
var k = Math.floor(array.length * (p / 100));
|
|
48498
|
-
array.sort(function (a, b) {
|
|
48499
|
-
return a - b;
|
|
48500
48512
|
});
|
|
48501
|
-
return
|
|
48513
|
+
return circularView;
|
|
48502
48514
|
}
|
|
48503
48515
|
|
|
48504
48516
|
/*
|
|
@@ -48560,7 +48572,10 @@
|
|
|
48560
48572
|
this.showInsertions = false !== config.showInsertions;
|
|
48561
48573
|
this.showMismatches = false !== config.showMismatches;
|
|
48562
48574
|
this.color = config.color;
|
|
48563
|
-
this.coverageColor = config.coverageColor;
|
|
48575
|
+
this.coverageColor = config.coverageColor;
|
|
48576
|
+
this.minFragmentLength = config.minFragmentLength; // Optional, might be undefined
|
|
48577
|
+
|
|
48578
|
+
this.maxFragmentLength = config.maxFragmentLength || 1000; // The sort object can be an array in the case of multi-locus view, however if multiple sort positions
|
|
48564
48579
|
// are present for a given reference frame the last one will take precedence
|
|
48565
48580
|
|
|
48566
48581
|
if (config.sort) {
|
|
@@ -48588,22 +48603,12 @@
|
|
|
48588
48603
|
return this._height;
|
|
48589
48604
|
}
|
|
48590
48605
|
|
|
48591
|
-
get minTemplateLength() {
|
|
48592
|
-
const configMinTLEN = this.config.minTLEN !== undefined ? this.config.minTLEN : this.config.minFragmentLength;
|
|
48593
|
-
return configMinTLEN !== undefined ? configMinTLEN : this._pairedEndStats ? this._pairedEndStats.minTLEN : 0;
|
|
48594
|
-
}
|
|
48595
|
-
|
|
48596
|
-
get maxTemplateLength() {
|
|
48597
|
-
const configMaxTLEN = this.config.maxTLEN !== undefined ? this.config.maxTLEN : this.config.maxFragmentLength;
|
|
48598
|
-
return configMaxTLEN !== undefined ? configMaxTLEN : this._pairedEndStats ? this._pairedEndStats.maxTLEN : 1000;
|
|
48599
|
-
}
|
|
48600
|
-
|
|
48601
48606
|
sort(options) {
|
|
48602
48607
|
options = this.assignSort(options);
|
|
48603
48608
|
|
|
48604
48609
|
for (let vp of this.trackView.viewports) {
|
|
48605
48610
|
if (vp.containsPosition(options.chr, options.position)) {
|
|
48606
|
-
const alignmentContainer = vp.
|
|
48611
|
+
const alignmentContainer = vp.getCachedFeatures();
|
|
48607
48612
|
|
|
48608
48613
|
if (alignmentContainer) {
|
|
48609
48614
|
sortAlignmentRows(options, alignmentContainer);
|
|
@@ -48638,16 +48643,16 @@
|
|
|
48638
48643
|
async getFeatures(chr, bpStart, bpEnd, bpPerPixel, viewport) {
|
|
48639
48644
|
const alignmentContainer = await this.featureSource.getAlignments(chr, bpStart, bpEnd);
|
|
48640
48645
|
|
|
48641
|
-
if (alignmentContainer.
|
|
48642
|
-
|
|
48646
|
+
if (alignmentContainer.alignments && alignmentContainer.alignments.length > 99) {
|
|
48647
|
+
if (undefined === this.minFragmentLength) {
|
|
48648
|
+
this.minFragmentLength = alignmentContainer.pairedEndStats.lowerFragmentLength;
|
|
48649
|
+
}
|
|
48643
48650
|
|
|
48644
|
-
if (
|
|
48645
|
-
this.
|
|
48651
|
+
if (undefined === this.maxFragmentLength) {
|
|
48652
|
+
this.maxFragmentLength = alignmentContainer.pairedEndStats.upperFragmentLength;
|
|
48646
48653
|
}
|
|
48647
48654
|
}
|
|
48648
48655
|
|
|
48649
|
-
alignmentContainer.alignments = undefined; // Don't need to hold onto these anymore
|
|
48650
|
-
|
|
48651
48656
|
const sort = this.sortObject;
|
|
48652
48657
|
|
|
48653
48658
|
if (sort) {
|
|
@@ -48752,7 +48757,7 @@
|
|
|
48752
48757
|
label: 'pair orientation'
|
|
48753
48758
|
});
|
|
48754
48759
|
colorByMenuItems.push({
|
|
48755
|
-
key: '
|
|
48760
|
+
key: 'fragmentLength',
|
|
48756
48761
|
label: 'insert size (TLEN)'
|
|
48757
48762
|
});
|
|
48758
48763
|
colorByMenuItems.push({
|
|
@@ -48863,7 +48868,7 @@
|
|
|
48863
48868
|
this.trackView.repaintViews();
|
|
48864
48869
|
}
|
|
48865
48870
|
});
|
|
48866
|
-
} //
|
|
48871
|
+
} // Experimental JBrowse feature
|
|
48867
48872
|
|
|
48868
48873
|
|
|
48869
48874
|
if (this.browser.circularView && true === this.browser.circularViewVisible && (this.alignmentTrack.hasPairs || this.alignmentTrack.hasSupplemental)) {
|
|
@@ -48873,9 +48878,26 @@
|
|
|
48873
48878
|
menuItems.push({
|
|
48874
48879
|
label: 'Add discordant pairs to circular view',
|
|
48875
48880
|
click: () => {
|
|
48881
|
+
const maxFragmentLength = this.maxFragmentLength;
|
|
48882
|
+
const inView = [];
|
|
48883
|
+
|
|
48876
48884
|
for (let viewport of this.trackView.viewports) {
|
|
48877
|
-
|
|
48885
|
+
for (let a of viewport.getCachedFeatures().allAlignments()) {
|
|
48886
|
+
const referenceFrame = viewport.referenceFrame;
|
|
48887
|
+
|
|
48888
|
+
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxFragmentLength)) {
|
|
48889
|
+
inView.push(a);
|
|
48890
|
+
}
|
|
48891
|
+
}
|
|
48878
48892
|
}
|
|
48893
|
+
|
|
48894
|
+
this.browser.circularViewVisible = true;
|
|
48895
|
+
const chords = makePairedAlignmentChords(inView);
|
|
48896
|
+
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02);
|
|
48897
|
+
this.browser.circularView.addChords(chords, {
|
|
48898
|
+
track: this.name,
|
|
48899
|
+
color: color
|
|
48900
|
+
});
|
|
48879
48901
|
}
|
|
48880
48902
|
});
|
|
48881
48903
|
}
|
|
@@ -48884,9 +48906,25 @@
|
|
|
48884
48906
|
menuItems.push({
|
|
48885
48907
|
label: 'Add split reads to circular view',
|
|
48886
48908
|
click: () => {
|
|
48909
|
+
const inView = [];
|
|
48910
|
+
|
|
48887
48911
|
for (let viewport of this.trackView.viewports) {
|
|
48888
|
-
|
|
48912
|
+
for (let a of viewport.getCachedFeatures().allAlignments()) {
|
|
48913
|
+
const referenceFrame = viewport.referenceFrame;
|
|
48914
|
+
const sa = a.hasTag('SA');
|
|
48915
|
+
|
|
48916
|
+
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && sa) {
|
|
48917
|
+
inView.push(a);
|
|
48918
|
+
}
|
|
48919
|
+
}
|
|
48889
48920
|
}
|
|
48921
|
+
|
|
48922
|
+
const chords = makeSupplementalAlignmentChords(inView);
|
|
48923
|
+
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.1);
|
|
48924
|
+
this.browser.circularView.addChords(chords, {
|
|
48925
|
+
track: this.name,
|
|
48926
|
+
color: color
|
|
48927
|
+
});
|
|
48890
48928
|
}
|
|
48891
48929
|
});
|
|
48892
48930
|
}
|
|
@@ -49005,7 +49043,7 @@
|
|
|
49005
49043
|
}
|
|
49006
49044
|
|
|
49007
49045
|
getCachedAlignmentContainers() {
|
|
49008
|
-
return this.trackView.viewports.map(vp => vp.
|
|
49046
|
+
return this.trackView.viewports.map(vp => vp.getCachedFeatures());
|
|
49009
49047
|
}
|
|
49010
49048
|
|
|
49011
49049
|
get dataRange() {
|
|
@@ -49031,56 +49069,6 @@
|
|
|
49031
49069
|
set autoscale(autoscale) {
|
|
49032
49070
|
this.coverageTrack.autoscale = autoscale;
|
|
49033
49071
|
}
|
|
49034
|
-
/**
|
|
49035
|
-
* Add chords to the circular view for the given viewport, represented by its reference frame
|
|
49036
|
-
* @param refFrame
|
|
49037
|
-
*/
|
|
49038
|
-
|
|
49039
|
-
|
|
49040
|
-
addPairedChordsForViewport(viewport) {
|
|
49041
|
-
const maxTemplateLength = this.maxTemplateLength;
|
|
49042
|
-
const inView = [];
|
|
49043
|
-
const refFrame = viewport.referenceFrame;
|
|
49044
|
-
|
|
49045
|
-
for (let a of viewport.cachedFeatures.allAlignments()) {
|
|
49046
|
-
if (a.end >= refFrame.start && a.start <= refFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxTemplateLength)) {
|
|
49047
|
-
inView.push(a);
|
|
49048
|
-
}
|
|
49049
|
-
}
|
|
49050
|
-
|
|
49051
|
-
const chords = makePairedAlignmentChords(inView);
|
|
49052
|
-
sendChords(chords, this, refFrame, 0.02); // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
|
|
49053
|
-
// const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
|
|
49054
|
-
//
|
|
49055
|
-
// // name the chord set to include track name and locus
|
|
49056
|
-
// const encodedName = this.name.replaceAll(' ', '%20')
|
|
49057
|
-
// const chordSetName = "all" === refFrame.chr ? encodedName :
|
|
49058
|
-
// `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
|
|
49059
|
-
// this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
49060
|
-
}
|
|
49061
|
-
|
|
49062
|
-
addSplitChordsForViewport(viewport) {
|
|
49063
|
-
const inView = [];
|
|
49064
|
-
const refFrame = viewport.referenceFrame;
|
|
49065
|
-
|
|
49066
|
-
for (let a of viewport.cachedFeatures.allAlignments()) {
|
|
49067
|
-
const sa = a.hasTag('SA');
|
|
49068
|
-
|
|
49069
|
-
if (a.end >= refFrame.start && a.start <= refFrame.end && sa) {
|
|
49070
|
-
inView.push(a);
|
|
49071
|
-
}
|
|
49072
|
-
}
|
|
49073
|
-
|
|
49074
|
-
const chords = makeSupplementalAlignmentChords(inView);
|
|
49075
|
-
sendChords(chords, this, refFrame, 0.02); // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
|
|
49076
|
-
// const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
|
|
49077
|
-
//
|
|
49078
|
-
// // name the chord set to include track name and locus
|
|
49079
|
-
// const encodedName = this.name.replaceAll(' ', '%20')
|
|
49080
|
-
// const chordSetName = "all" === refFrame.chr ? encodedName :
|
|
49081
|
-
// `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
|
|
49082
|
-
// this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
49083
|
-
}
|
|
49084
49072
|
|
|
49085
49073
|
}
|
|
49086
49074
|
|
|
@@ -49191,7 +49179,7 @@
|
|
|
49191
49179
|
}
|
|
49192
49180
|
|
|
49193
49181
|
getClickedObject(clickState) {
|
|
49194
|
-
let features = clickState.viewport.
|
|
49182
|
+
let features = clickState.viewport.getCachedFeatures();
|
|
49195
49183
|
if (!features || features.length === 0) return;
|
|
49196
49184
|
const genomicLocation = Math.floor(clickState.genomicLocation);
|
|
49197
49185
|
const coverageMap = features.coverageMap;
|
|
@@ -49277,14 +49265,14 @@
|
|
|
49277
49265
|
this.deletionColor = config.deletionColor || "black";
|
|
49278
49266
|
this.skippedColor = config.skippedColor || "rgb(150, 170, 170)";
|
|
49279
49267
|
this.pairConnectorColor = config.pairConnectorColor;
|
|
49280
|
-
this.
|
|
49281
|
-
this.
|
|
49268
|
+
this.smallFragmentLengthColor = config.smallFragmentLengthColor || "rgb(0, 0, 150)";
|
|
49269
|
+
this.largeFragmentLengthColor = config.largeFragmentLengthColor || "rgb(200, 0, 0)";
|
|
49282
49270
|
this.pairOrientation = config.pairOrienation || 'fr';
|
|
49283
49271
|
this.pairColors = {};
|
|
49284
49272
|
this.pairColors["RL"] = config.rlColor || "rgb(0, 150, 0)";
|
|
49285
49273
|
this.pairColors["RR"] = config.rrColor || "rgb(20, 50, 200)";
|
|
49286
49274
|
this.pairColors["LL"] = config.llColor || "rgb(0, 150, 150)";
|
|
49287
|
-
this.colorBy = config.colorBy || "
|
|
49275
|
+
this.colorBy = config.colorBy || "pairOrientation";
|
|
49288
49276
|
this.colorByTag = config.colorByTag ? config.colorByTag.toUpperCase() : undefined;
|
|
49289
49277
|
this.bamColorTag = config.bamColorTag === undefined ? "YC" : config.bamColorTag;
|
|
49290
49278
|
this.hideSmallIndels = config.hideSmallIndels;
|
|
@@ -49639,7 +49627,7 @@
|
|
|
49639
49627
|
direction: direction
|
|
49640
49628
|
};
|
|
49641
49629
|
this.parent.sortObject = newSortObject;
|
|
49642
|
-
sortAlignmentRows(newSortObject, viewport.
|
|
49630
|
+
sortAlignmentRows(newSortObject, viewport.getCachedFeatures());
|
|
49643
49631
|
viewport.repaint();
|
|
49644
49632
|
};
|
|
49645
49633
|
|
|
@@ -49691,7 +49679,7 @@
|
|
|
49691
49679
|
};
|
|
49692
49680
|
this.sortByTag = tag;
|
|
49693
49681
|
this.parent.sortObject = newSortObject;
|
|
49694
|
-
sortAlignmentRows(newSortObject, viewport.
|
|
49682
|
+
sortAlignmentRows(newSortObject, viewport.getCachedFeatures());
|
|
49695
49683
|
viewport.repaint();
|
|
49696
49684
|
}
|
|
49697
49685
|
}
|
|
@@ -49715,12 +49703,8 @@
|
|
|
49715
49703
|
const referenceFrame = clickState.viewport.referenceFrame;
|
|
49716
49704
|
|
|
49717
49705
|
if (this.browser.genome.getChromosome(clickedAlignment.mate.chr)) {
|
|
49718
|
-
this.highlightedAlignmentReadNamed = clickedAlignment.readName;
|
|
49719
|
-
|
|
49720
|
-
const bpWidth = referenceFrame.end - referenceFrame.start;
|
|
49721
|
-
const frameStart = clickedAlignment.mate.position - bpWidth / 2;
|
|
49722
|
-
const frameEnd = clickedAlignment.mate.position + bpWidth / 2;
|
|
49723
|
-
this.browser.addMultiLocusPanel(clickedAlignment.mate.chr, frameStart, frameEnd, referenceFrame);
|
|
49706
|
+
this.highlightedAlignmentReadNamed = clickedAlignment.readName;
|
|
49707
|
+
this.browser.presentMultiLocusPanel(clickedAlignment, referenceFrame);
|
|
49724
49708
|
} else {
|
|
49725
49709
|
Alert.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
|
|
49726
49710
|
}
|
|
@@ -49768,7 +49752,20 @@
|
|
|
49768
49752
|
list.push({
|
|
49769
49753
|
label: 'Add discordant pairs to circular view',
|
|
49770
49754
|
click: () => {
|
|
49771
|
-
this.parent.
|
|
49755
|
+
const maxFragmentLength = this.parent.maxFragmentLength;
|
|
49756
|
+
const {
|
|
49757
|
+
referenceFrame
|
|
49758
|
+
} = viewport;
|
|
49759
|
+
const inView = viewport.getCachedFeatures().allAlignments().filter(a => {
|
|
49760
|
+
return a.end >= referenceFrame.start && a.start <= referenceFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxFragmentLength);
|
|
49761
|
+
});
|
|
49762
|
+
this.browser.circularViewVisible = true;
|
|
49763
|
+
const chords = makePairedAlignmentChords(inView);
|
|
49764
|
+
const color = IGVColor.addAlpha(this.parent.color || 'rgb(0,0,255)', 0.02);
|
|
49765
|
+
this.browser.circularView.addChords(chords, {
|
|
49766
|
+
track: this.parent.name,
|
|
49767
|
+
color: color
|
|
49768
|
+
});
|
|
49772
49769
|
}
|
|
49773
49770
|
});
|
|
49774
49771
|
}
|
|
@@ -49777,7 +49774,23 @@
|
|
|
49777
49774
|
list.push({
|
|
49778
49775
|
label: 'Add split reads to circular view',
|
|
49779
49776
|
click: () => {
|
|
49780
|
-
|
|
49777
|
+
const inView = [];
|
|
49778
|
+
|
|
49779
|
+
for (let a of viewport.getCachedFeatures().allAlignments()) {
|
|
49780
|
+
const referenceFrame = viewport.referenceFrame;
|
|
49781
|
+
const sa = a.hasTag('SA');
|
|
49782
|
+
|
|
49783
|
+
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && sa) {
|
|
49784
|
+
inView.push(a);
|
|
49785
|
+
}
|
|
49786
|
+
}
|
|
49787
|
+
|
|
49788
|
+
const chords = makeSupplementalAlignmentChords(inView);
|
|
49789
|
+
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.1);
|
|
49790
|
+
this.browser.circularView.addChords(chords, {
|
|
49791
|
+
track: this.name,
|
|
49792
|
+
color: color
|
|
49793
|
+
});
|
|
49781
49794
|
}
|
|
49782
49795
|
});
|
|
49783
49796
|
}
|
|
@@ -49793,7 +49806,7 @@
|
|
|
49793
49806
|
const y = clickState.y;
|
|
49794
49807
|
const genomicLocation = clickState.genomicLocation;
|
|
49795
49808
|
const showSoftClips = this.parent.showSoftClips;
|
|
49796
|
-
let features = viewport.
|
|
49809
|
+
let features = viewport.getCachedFeatures();
|
|
49797
49810
|
if (!features || features.length === 0) return;
|
|
49798
49811
|
let packedAlignmentRows = features.packedAlignmentRows;
|
|
49799
49812
|
let downsampledIntervals = features.downsampledIntervals;
|
|
@@ -49879,16 +49892,13 @@
|
|
|
49879
49892
|
break;
|
|
49880
49893
|
}
|
|
49881
49894
|
|
|
49882
|
-
case "tlen":
|
|
49883
49895
|
case "fragmentLength":
|
|
49884
|
-
if (alignment.mate && alignment.isMateMapped()) {
|
|
49885
|
-
|
|
49886
|
-
|
|
49887
|
-
|
|
49888
|
-
|
|
49889
|
-
|
|
49890
|
-
color = this.largeTLENColor;
|
|
49891
|
-
}
|
|
49896
|
+
if (alignment.mate && alignment.isMateMapped() && alignment.mate.chr !== alignment.chr) {
|
|
49897
|
+
color = getChrColor(alignment.mate.chr);
|
|
49898
|
+
} else if (this.parent.minFragmentLength && Math.abs(alignment.fragmentLength) < this.parent.minFragmentLength) {
|
|
49899
|
+
color = this.smallFragmentLengthColor;
|
|
49900
|
+
} else if (this.parent.maxFragmentLength && Math.abs(alignment.fragmentLength) > this.parent.maxFragmentLength) {
|
|
49901
|
+
color = this.largeFragmentLengthColor;
|
|
49892
49902
|
}
|
|
49893
49903
|
|
|
49894
49904
|
break;
|
|
@@ -49930,7 +49940,10 @@
|
|
|
49930
49940
|
alignmentContainer.packedAlignmentRows.sort(function (rowA, rowB) {
|
|
49931
49941
|
const i = rowA.score > rowB.score ? 1 : rowA.score < rowB.score ? -1 : 0;
|
|
49932
49942
|
return true === direction ? i : -i;
|
|
49933
|
-
});
|
|
49943
|
+
}); // For debugging
|
|
49944
|
+
// for(let r of alignmentContainer.packedAlignmentRows) {
|
|
49945
|
+
// console.log(r.score);
|
|
49946
|
+
// }
|
|
49934
49947
|
}
|
|
49935
49948
|
|
|
49936
49949
|
function shadedBaseColor(qual, baseColor) {
|
|
@@ -50085,7 +50098,7 @@
|
|
|
50085
50098
|
});
|
|
50086
50099
|
this.$viewport.append(this.$rulerLabel);
|
|
50087
50100
|
this.$rulerLabel.click(async () => {
|
|
50088
|
-
await this.browser.
|
|
50101
|
+
await this.browser.selectMultiLocusPanel(this.referenceFrame); // const removals = this.browser.referenceFrameList.filter(r => this.referenceFrame !== r)
|
|
50089
50102
|
// for (let referenceFrame of removals) {
|
|
50090
50103
|
// await this.browser.removeMultiLocusPanel(referenceFrame)
|
|
50091
50104
|
// }
|
|
@@ -50400,7 +50413,7 @@
|
|
|
50400
50413
|
referenceFrame.start = ss;
|
|
50401
50414
|
referenceFrame.end = ee;
|
|
50402
50415
|
referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
50403
|
-
this.browser.updateViews(true);
|
|
50416
|
+
this.browser.updateViews(referenceFrame, this.browser.trackViews, true);
|
|
50404
50417
|
}
|
|
50405
50418
|
|
|
50406
50419
|
this.boundClickHandler = clickHandler.bind(this);
|
|
@@ -51277,9 +51290,7 @@
|
|
|
51277
51290
|
|
|
51278
51291
|
repaintViews() {
|
|
51279
51292
|
for (let viewport of this.viewports) {
|
|
51280
|
-
|
|
51281
|
-
viewport.repaint();
|
|
51282
|
-
}
|
|
51293
|
+
viewport.repaint();
|
|
51283
51294
|
}
|
|
51284
51295
|
|
|
51285
51296
|
if (typeof this.track.paintAxis === 'function') {
|
|
@@ -51303,9 +51314,6 @@
|
|
|
51303
51314
|
}
|
|
51304
51315
|
/**
|
|
51305
51316
|
* Update viewports to reflect current genomic state, possibly loading additional data.
|
|
51306
|
-
*
|
|
51307
|
-
* @param force - if true, force a repaint even if no new data is loaded
|
|
51308
|
-
* @returns {Promise<void>}
|
|
51309
51317
|
*/
|
|
51310
51318
|
|
|
51311
51319
|
|
|
@@ -51321,7 +51329,7 @@
|
|
|
51321
51329
|
} // rpv: viewports whose image (canvas) does not fully cover current genomic range
|
|
51322
51330
|
|
|
51323
51331
|
|
|
51324
|
-
const reloadableViewports =
|
|
51332
|
+
const reloadableViewports = this.viewportsToReload(force); // Trigger viewport to load features needed to cover current genomic range
|
|
51325
51333
|
// NOTE: these must be loaded synchronously, do not user Promise.all, not all file readers are thread safe
|
|
51326
51334
|
|
|
51327
51335
|
for (let viewport of reloadableViewports) {
|
|
@@ -51329,7 +51337,7 @@
|
|
|
51329
51337
|
}
|
|
51330
51338
|
|
|
51331
51339
|
if (this.disposed) return; // Track was removed during load
|
|
51332
|
-
//
|
|
51340
|
+
// Very special case for variant tracks in multilocus view. The # of rows to allocate to the variant (site)
|
|
51333
51341
|
// section depends on data from all the views. We only need to adjust this however if any data was loaded
|
|
51334
51342
|
// (i.e. reloadableViewports.length > 0)
|
|
51335
51343
|
|
|
@@ -51337,8 +51345,8 @@
|
|
|
51337
51345
|
let maxRow = 0;
|
|
51338
51346
|
|
|
51339
51347
|
for (let viewport of this.viewports) {
|
|
51340
|
-
if (viewport.
|
|
51341
|
-
maxRow = Math.max(maxRow, viewport.
|
|
51348
|
+
if (viewport.tile && viewport.tile.features) {
|
|
51349
|
+
maxRow = Math.max(maxRow, viewport.tile.features.reduce((a, f) => Math.max(a, f.row || 0), 0));
|
|
51342
51350
|
}
|
|
51343
51351
|
}
|
|
51344
51352
|
|
|
@@ -51361,14 +51369,14 @@
|
|
|
51361
51369
|
const start = referenceFrame.start;
|
|
51362
51370
|
const end = start + referenceFrame.toBP($$1(visibleViewport.contentDiv).width());
|
|
51363
51371
|
|
|
51364
|
-
if (visibleViewport.
|
|
51365
|
-
if (typeof visibleViewport.
|
|
51366
|
-
const max = visibleViewport.
|
|
51372
|
+
if (visibleViewport.tile && visibleViewport.tile.features) {
|
|
51373
|
+
if (typeof visibleViewport.tile.features.getMax === 'function') {
|
|
51374
|
+
const max = visibleViewport.tile.features.getMax(start, end);
|
|
51367
51375
|
allFeatures.push({
|
|
51368
51376
|
value: max
|
|
51369
51377
|
});
|
|
51370
51378
|
} else {
|
|
51371
|
-
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(visibleViewport.
|
|
51379
|
+
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(visibleViewport.tile.features, start, end));
|
|
51372
51380
|
}
|
|
51373
51381
|
}
|
|
51374
51382
|
}
|
|
@@ -51378,22 +51386,16 @@
|
|
|
51378
51386
|
} else {
|
|
51379
51387
|
this.track.dataRange = doAutoscale(allFeatures);
|
|
51380
51388
|
}
|
|
51381
|
-
} // Must repaint all viewports if autoscaling
|
|
51389
|
+
} // Must repaint all viewports if autoscaling
|
|
51382
51390
|
|
|
51383
51391
|
|
|
51384
|
-
if (this.track.autoscale || this.track.autoscaleGroup
|
|
51385
|
-
for (let
|
|
51386
|
-
|
|
51392
|
+
if (!isDragging && (this.track.autoscale || this.track.autoscaleGroup)) {
|
|
51393
|
+
for (let visibleViewport of visibleViewports) {
|
|
51394
|
+
visibleViewport.repaint();
|
|
51387
51395
|
}
|
|
51388
51396
|
} else {
|
|
51389
|
-
|
|
51390
|
-
|
|
51391
|
-
for (let vp of visibleViewports) {
|
|
51392
|
-
const invalid = vp.canvas && vp.canvas._data && vp.canvas._data.invalidate;
|
|
51393
|
-
|
|
51394
|
-
if (invalid || reloadedViewports.has(vp)) {
|
|
51395
|
-
vp.repaint();
|
|
51396
|
-
}
|
|
51397
|
+
for (let vp of reloadableViewports) {
|
|
51398
|
+
vp.repaint();
|
|
51397
51399
|
}
|
|
51398
51400
|
}
|
|
51399
51401
|
|
|
@@ -51421,13 +51423,13 @@
|
|
|
51421
51423
|
*/
|
|
51422
51424
|
|
|
51423
51425
|
|
|
51424
|
-
async getInViewFeatures() {
|
|
51426
|
+
async getInViewFeatures(force) {
|
|
51425
51427
|
if (!(this.browser && this.browser.referenceFrameList)) {
|
|
51426
51428
|
return [];
|
|
51427
51429
|
} // List of viewports that need reloading
|
|
51428
51430
|
|
|
51429
51431
|
|
|
51430
|
-
const rpV = this.viewportsToReload();
|
|
51432
|
+
const rpV = this.viewportsToReload(force);
|
|
51431
51433
|
const promises = rpV.map(function (vp) {
|
|
51432
51434
|
return vp.loadFeatures();
|
|
51433
51435
|
});
|
|
@@ -51435,18 +51437,18 @@
|
|
|
51435
51437
|
let allFeatures = [];
|
|
51436
51438
|
|
|
51437
51439
|
for (let vp of this.viewports) {
|
|
51438
|
-
if (vp.
|
|
51440
|
+
if (vp.tile && vp.tile.features) {
|
|
51439
51441
|
const referenceFrame = vp.referenceFrame;
|
|
51440
51442
|
const start = referenceFrame.start;
|
|
51441
51443
|
const end = start + referenceFrame.toBP($$1(vp.contentDiv).width());
|
|
51442
51444
|
|
|
51443
|
-
if (typeof vp.
|
|
51444
|
-
const max = vp.
|
|
51445
|
+
if (typeof vp.tile.features.getMax === 'function') {
|
|
51446
|
+
const max = vp.tile.features.getMax(start, end);
|
|
51445
51447
|
allFeatures.push({
|
|
51446
51448
|
value: max
|
|
51447
51449
|
});
|
|
51448
51450
|
} else {
|
|
51449
|
-
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(vp.
|
|
51451
|
+
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(vp.tile.features, start, end));
|
|
51450
51452
|
}
|
|
51451
51453
|
}
|
|
51452
51454
|
}
|
|
@@ -51503,7 +51505,7 @@
|
|
|
51503
51505
|
const start = referenceFrame.start;
|
|
51504
51506
|
const end = start + referenceFrame.toBP($$1(viewport.contentDiv).width());
|
|
51505
51507
|
const bpPerPixel = referenceFrame.bpPerPixel;
|
|
51506
|
-
return !viewport.
|
|
51508
|
+
return force || !viewport.tile || viewport.tile.invalidate || !viewport.tile.containsRange(chr, start, end, bpPerPixel);
|
|
51507
51509
|
}
|
|
51508
51510
|
});
|
|
51509
51511
|
return viewports;
|
|
@@ -56325,7 +56327,7 @@
|
|
|
56325
56327
|
}
|
|
56326
56328
|
|
|
56327
56329
|
this.queryable = false;
|
|
56328
|
-
this.featureCache = new FeatureCache
|
|
56330
|
+
this.featureCache = new FeatureCache(features, genome);
|
|
56329
56331
|
} else if (config.reader) {
|
|
56330
56332
|
// Explicit reader implementation
|
|
56331
56333
|
this.reader = config.reader;
|
|
@@ -56496,13 +56498,13 @@
|
|
|
56496
56498
|
} // Note - replacing previous cache with new one. genomicInterval is optional (might be undefined => includes all features)
|
|
56497
56499
|
|
|
56498
56500
|
|
|
56499
|
-
this.featureCache = new FeatureCache
|
|
56501
|
+
this.featureCache = new FeatureCache(features, this.genome, genomicInterval); // If track is marked "searchable"< cache features by name -- use this with caution, memory intensive
|
|
56500
56502
|
|
|
56501
56503
|
if (this.config.searchable || this.config.searchableFields) {
|
|
56502
56504
|
this.addFeaturesToDB(features);
|
|
56503
56505
|
}
|
|
56504
56506
|
} else {
|
|
56505
|
-
this.featureCache = new FeatureCache
|
|
56507
|
+
this.featureCache = new FeatureCache([], genomicInterval); // Empty cache
|
|
56506
56508
|
}
|
|
56507
56509
|
}
|
|
56508
56510
|
|
|
@@ -58489,7 +58491,7 @@
|
|
|
58489
58491
|
// single-exon transcript
|
|
58490
58492
|
const xLeft = Math.max(0, coord.px);
|
|
58491
58493
|
const xRight = Math.min(pixelWidth, coord.px1);
|
|
58492
|
-
const width =
|
|
58494
|
+
const width = xRight - xLeft;
|
|
58493
58495
|
ctx.fillRect(xLeft, py, width, h); // Arrows
|
|
58494
58496
|
// Do not draw if strand is not +/-
|
|
58495
58497
|
|
|
@@ -59273,12 +59275,14 @@
|
|
|
59273
59275
|
this.featureType = 'numeric';
|
|
59274
59276
|
this.paintAxis = paintAxis;
|
|
59275
59277
|
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
59276
|
-
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59277
|
-
this.logScale = config.logScale ? config.logScale : false;
|
|
59278
59278
|
|
|
59279
59279
|
if ("bigwig" === format) {
|
|
59280
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59281
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
59280
59282
|
this.featureSource = new BWSource(config, this.browser.genome);
|
|
59281
59283
|
} else if ("tdf" === format) {
|
|
59284
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59285
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
59282
59286
|
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
59283
59287
|
} else {
|
|
59284
59288
|
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
@@ -60055,7 +60059,7 @@
|
|
|
60055
60059
|
|
|
60056
60060
|
const sortHandler = sort => {
|
|
60057
60061
|
const viewport = clickState.viewport;
|
|
60058
|
-
const features = viewport.
|
|
60062
|
+
const features = viewport.getCachedFeatures();
|
|
60059
60063
|
this.sortSamples(sort.chr, sort.start, sort.end, sort.direction, features);
|
|
60060
60064
|
};
|
|
60061
60065
|
|
|
@@ -60161,16 +60165,10 @@
|
|
|
60161
60165
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
60162
60166
|
* THE SOFTWARE.
|
|
60163
60167
|
*/
|
|
60164
|
-
/**
|
|
60165
|
-
* Represents 2 or more wig tracks overlaid on a common viewport.
|
|
60166
|
-
*/
|
|
60167
60168
|
|
|
60168
60169
|
class MergedTrack extends TrackBase {
|
|
60169
60170
|
constructor(config, browser) {
|
|
60170
60171
|
super(config, browser);
|
|
60171
|
-
this.type = "merged";
|
|
60172
|
-
this.featureType = 'numeric';
|
|
60173
|
-
this.paintAxis = paintAxis;
|
|
60174
60172
|
}
|
|
60175
60173
|
|
|
60176
60174
|
init(config) {
|
|
@@ -60181,6 +60179,21 @@
|
|
|
60181
60179
|
super.init(config);
|
|
60182
60180
|
}
|
|
60183
60181
|
|
|
60182
|
+
get height() {
|
|
60183
|
+
return this._height;
|
|
60184
|
+
}
|
|
60185
|
+
|
|
60186
|
+
set height(h) {
|
|
60187
|
+
this._height = h;
|
|
60188
|
+
|
|
60189
|
+
if (this.tracks) {
|
|
60190
|
+
for (let t of this.tracks) {
|
|
60191
|
+
t.height = h;
|
|
60192
|
+
t.config.height = h;
|
|
60193
|
+
}
|
|
60194
|
+
}
|
|
60195
|
+
}
|
|
60196
|
+
|
|
60184
60197
|
async postInit() {
|
|
60185
60198
|
this.tracks = [];
|
|
60186
60199
|
const p = [];
|
|
@@ -60202,83 +60215,45 @@
|
|
|
60202
60215
|
}
|
|
60203
60216
|
}
|
|
60204
60217
|
|
|
60205
|
-
this.
|
|
60206
|
-
this.logScale = this.config.logScale ? this.config.logScale : false;
|
|
60207
|
-
this.autoscale = this.config.autoscale || this.config.max === undefined;
|
|
60208
|
-
|
|
60209
|
-
if (!this.autoscale) {
|
|
60210
|
-
this.dataRange = {
|
|
60211
|
-
min: this.config.min || 0,
|
|
60212
|
-
max: this.config.max
|
|
60213
|
-
};
|
|
60214
|
-
}
|
|
60215
|
-
|
|
60216
|
-
for (let t of this.tracks) {
|
|
60217
|
-
t.autoscale = false;
|
|
60218
|
-
t.dataRange = this.dataRange;
|
|
60219
|
-
}
|
|
60220
|
-
|
|
60221
|
-
this.height = this.config.height || 50;
|
|
60218
|
+
this.height = this.config.height || 100;
|
|
60222
60219
|
return Promise.all(p);
|
|
60223
60220
|
}
|
|
60224
60221
|
|
|
60225
|
-
get height() {
|
|
60226
|
-
return this._height;
|
|
60227
|
-
}
|
|
60228
|
-
|
|
60229
|
-
set height(h) {
|
|
60230
|
-
this._height = h;
|
|
60231
|
-
|
|
60232
|
-
if (this.tracks) {
|
|
60233
|
-
for (let t of this.tracks) {
|
|
60234
|
-
t.height = h;
|
|
60235
|
-
t.config.height = h;
|
|
60236
|
-
}
|
|
60237
|
-
}
|
|
60238
|
-
}
|
|
60239
|
-
|
|
60240
|
-
menuItemList() {
|
|
60241
|
-
let items = [];
|
|
60242
|
-
|
|
60243
|
-
if (this.flipAxis !== undefined) {
|
|
60244
|
-
items.push({
|
|
60245
|
-
label: "Flip y-axis",
|
|
60246
|
-
click: () => {
|
|
60247
|
-
this.flipAxis = !this.flipAxis;
|
|
60248
|
-
this.trackView.repaintViews();
|
|
60249
|
-
}
|
|
60250
|
-
});
|
|
60251
|
-
}
|
|
60252
|
-
|
|
60253
|
-
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
60254
|
-
return items;
|
|
60255
|
-
}
|
|
60256
|
-
|
|
60257
60222
|
async getFeatures(chr, bpStart, bpEnd, bpPerPixel) {
|
|
60258
60223
|
const promises = this.tracks.map(t => t.getFeatures(chr, bpStart, bpEnd, bpPerPixel));
|
|
60259
60224
|
return Promise.all(promises);
|
|
60260
60225
|
}
|
|
60261
60226
|
|
|
60262
60227
|
draw(options) {
|
|
60263
|
-
|
|
60228
|
+
var i, len, mergedFeatures, trackOptions, dataRange;
|
|
60229
|
+
mergedFeatures = options.features; // Array of feature arrays, 1 for each track
|
|
60264
60230
|
|
|
60265
|
-
|
|
60266
|
-
this.dataRange = autoscale(options.referenceFrame.chr, mergedFeatures);
|
|
60267
|
-
}
|
|
60231
|
+
dataRange = autoscale(options.referenceFrame.chr, mergedFeatures); //IGVGraphics.fillRect(options.context, 0, options.pixelTop, options.pixelWidth, options.pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
60268
60232
|
|
|
60269
|
-
for (
|
|
60270
|
-
|
|
60233
|
+
for (i = 0, len = this.tracks.length; i < len; i++) {
|
|
60234
|
+
trackOptions = Object.assign({}, options);
|
|
60271
60235
|
trackOptions.features = mergedFeatures[i];
|
|
60272
|
-
this.tracks[i].dataRange =
|
|
60273
|
-
this.tracks[i].flipAxis = this.flipAxis;
|
|
60274
|
-
this.tracks[i].logScale = this.logScale;
|
|
60275
|
-
this.tracks[i].graphType = this.graphType;
|
|
60236
|
+
this.tracks[i].dataRange = dataRange;
|
|
60276
60237
|
this.tracks[i].draw(trackOptions);
|
|
60277
60238
|
}
|
|
60278
60239
|
}
|
|
60279
60240
|
|
|
60241
|
+
paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
60242
|
+
var i, len, autoscale, track;
|
|
60243
|
+
autoscale = true; // Hardcoded for now
|
|
60244
|
+
|
|
60245
|
+
for (i = 0, len = this.tracks.length; i < len; i++) {
|
|
60246
|
+
track = this.tracks[i];
|
|
60247
|
+
|
|
60248
|
+
if (typeof track.paintAxis === 'function') {
|
|
60249
|
+
track.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
60250
|
+
if (autoscale) break;
|
|
60251
|
+
}
|
|
60252
|
+
}
|
|
60253
|
+
}
|
|
60254
|
+
|
|
60280
60255
|
popupData(clickState, features) {
|
|
60281
|
-
const featuresArray = features || clickState.viewport.
|
|
60256
|
+
const featuresArray = features || clickState.viewport.getCachedFeatures();
|
|
60282
60257
|
|
|
60283
60258
|
if (featuresArray && featuresArray.length === this.tracks.length) {
|
|
60284
60259
|
// Array of feature arrays, 1 for each track
|
|
@@ -60296,23 +60271,39 @@
|
|
|
60296
60271
|
}
|
|
60297
60272
|
|
|
60298
60273
|
supportsWholeGenome() {
|
|
60299
|
-
|
|
60274
|
+
const b = this.tracks.every(track => track.supportsWholeGenome());
|
|
60275
|
+
return b;
|
|
60300
60276
|
}
|
|
60301
60277
|
|
|
60302
60278
|
}
|
|
60303
60279
|
|
|
60304
60280
|
function autoscale(chr, featureArrays) {
|
|
60305
|
-
|
|
60306
|
-
|
|
60281
|
+
var min = 0,
|
|
60282
|
+
max = -Number.MAX_VALUE;
|
|
60283
|
+
// if (chr === 'all') {
|
|
60284
|
+
// allValues = [];
|
|
60285
|
+
// featureArrays.forEach(function (features) {
|
|
60286
|
+
// features.forEach(function (f) {
|
|
60287
|
+
// if (!Number.isNaN(f.value)) {
|
|
60288
|
+
// allValues.push(f.value);
|
|
60289
|
+
// }
|
|
60290
|
+
// });
|
|
60291
|
+
// });
|
|
60292
|
+
//
|
|
60293
|
+
// min = Math.min(0, IGVMath.percentile(allValues, .1));
|
|
60294
|
+
// max = IGVMath.percentile(allValues, 99.9);
|
|
60295
|
+
//
|
|
60296
|
+
// }
|
|
60297
|
+
// else {
|
|
60307
60298
|
|
|
60308
|
-
|
|
60309
|
-
|
|
60299
|
+
featureArrays.forEach(function (features, i) {
|
|
60300
|
+
features.forEach(function (f) {
|
|
60310
60301
|
if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
|
|
60311
60302
|
min = Math.min(min, f.value);
|
|
60312
60303
|
max = Math.max(max, f.value);
|
|
60313
60304
|
}
|
|
60314
|
-
}
|
|
60315
|
-
}
|
|
60305
|
+
});
|
|
60306
|
+
}); // }
|
|
60316
60307
|
|
|
60317
60308
|
return {
|
|
60318
60309
|
min: min,
|
|
@@ -60896,21 +60887,20 @@
|
|
|
60896
60887
|
const cachedFeatures = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end); // inView features are simply features that have been drawn, i.e. have a drawState
|
|
60897
60888
|
|
|
60898
60889
|
const inView = cachedFeatures.filter(f => f.drawState);
|
|
60899
|
-
if (inView.length === 0)
|
|
60890
|
+
if (inView.length === 0) erturn;
|
|
60900
60891
|
this.browser.circularViewVisible = true;
|
|
60901
|
-
const chords = makeBedPEChords(inView);
|
|
60902
|
-
|
|
60903
|
-
|
|
60904
|
-
|
|
60905
|
-
|
|
60906
|
-
|
|
60907
|
-
|
|
60908
|
-
|
|
60909
|
-
|
|
60910
|
-
|
|
60911
|
-
|
|
60912
|
-
|
|
60913
|
-
// this.browser.circularView.addChords(chords, {track: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
60892
|
+
const chords = makeBedPEChords(inView); // for filtered set, distinguishing the chromosomes is more critical than tracks
|
|
60893
|
+
|
|
60894
|
+
const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.5);
|
|
60895
|
+
const trackColor = IGVColor.addAlpha(this.color, 0.5); // name the chord set to include filtering information
|
|
60896
|
+
|
|
60897
|
+
const encodedName = this.name.replaceAll(' ', '%20');
|
|
60898
|
+
const chordSetName = "all" === refFrame.chr ? encodedName : `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end} ; range:${this.dataRange.min}-${this.dataRange.max})`;
|
|
60899
|
+
this.browser.circularView.addChords(chords, {
|
|
60900
|
+
track: chordSetName,
|
|
60901
|
+
color: chordSetColor,
|
|
60902
|
+
trackColor: trackColor
|
|
60903
|
+
});
|
|
60914
60904
|
}
|
|
60915
60905
|
|
|
60916
60906
|
doAutoscale(features) {
|
|
@@ -60997,7 +60987,7 @@
|
|
|
60997
60987
|
clickedFeatures(clickState, features) {
|
|
60998
60988
|
// We use the cached features rather than method to avoid async load. If the
|
|
60999
60989
|
// feature is not already loaded this won't work, but the user wouldn't be mousing over it either.
|
|
61000
|
-
const featureList = features || clickState.viewport.
|
|
60990
|
+
const featureList = features || clickState.viewport.getCachedFeatures();
|
|
61001
60991
|
const candidates = [];
|
|
61002
60992
|
|
|
61003
60993
|
if (featureList) {
|
|
@@ -61583,7 +61573,7 @@
|
|
|
61583
61573
|
variantColor = "gray";
|
|
61584
61574
|
}
|
|
61585
61575
|
} else if (this._color) {
|
|
61586
|
-
variantColor = this.
|
|
61576
|
+
variantColor = typeof this._color === "function" ? this._color(v) : this._color;
|
|
61587
61577
|
} else if ("NONVARIANT" === v.type) {
|
|
61588
61578
|
variantColor = this.nonRefColor;
|
|
61589
61579
|
} else if ("MIXED" === v.type) {
|
|
@@ -61595,10 +61585,6 @@
|
|
|
61595
61585
|
return variantColor;
|
|
61596
61586
|
}
|
|
61597
61587
|
|
|
61598
|
-
get color() {
|
|
61599
|
-
return this._color ? typeof this._color === "function" ? this._color(v) : this._color : this.defaultColor;
|
|
61600
|
-
}
|
|
61601
|
-
|
|
61602
61588
|
clickedFeatures(clickState, features) {
|
|
61603
61589
|
let featureList = super.clickedFeatures(clickState, features);
|
|
61604
61590
|
const vGap = this.displayMode === 'EXPANDED' ? this.expandedVGap : this.squishedVGap;
|
|
@@ -61864,10 +61850,24 @@
|
|
|
61864
61850
|
menuItems.push({
|
|
61865
61851
|
label: 'Add SVs to circular view',
|
|
61866
61852
|
click: () => {
|
|
61853
|
+
const inView = [];
|
|
61867
61854
|
|
|
61868
61855
|
for (let viewport of this.trackView.viewports) {
|
|
61869
|
-
|
|
61856
|
+
const refFrame = viewport.referenceFrame;
|
|
61857
|
+
|
|
61858
|
+
for (let f of viewport.getCachedFeatures()) {
|
|
61859
|
+
if (f.end >= refFrame.start && f.start <= refFrame.end) {
|
|
61860
|
+
inView.push(f);
|
|
61861
|
+
}
|
|
61862
|
+
}
|
|
61870
61863
|
}
|
|
61864
|
+
|
|
61865
|
+
const chords = makeVCFChords(inView);
|
|
61866
|
+
const color = IGVColor.addAlpha(this._color || this.defaultColor, 0.5);
|
|
61867
|
+
this.browser.circularView.addChords(chords, {
|
|
61868
|
+
track: this.name,
|
|
61869
|
+
color: color
|
|
61870
|
+
});
|
|
61871
61871
|
}
|
|
61872
61872
|
});
|
|
61873
61873
|
}
|
|
@@ -61883,20 +61883,20 @@
|
|
|
61883
61883
|
list.push({
|
|
61884
61884
|
label: 'Add SVs to Circular View',
|
|
61885
61885
|
click: () => {
|
|
61886
|
-
|
|
61886
|
+
const refFrame = viewport.referenceFrame;
|
|
61887
|
+
const inView = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
61888
|
+
const chords = makeVCFChords(inView);
|
|
61889
|
+
const color = IGVColor.addAlpha(this._color || this.defaultColor, 0.5);
|
|
61890
|
+
this.browser.circularView.addChords(chords, {
|
|
61891
|
+
track: this.name,
|
|
61892
|
+
color: color
|
|
61893
|
+
});
|
|
61887
61894
|
}
|
|
61888
61895
|
});
|
|
61889
61896
|
list.push('<hr/>');
|
|
61890
61897
|
return list;
|
|
61891
61898
|
}
|
|
61892
61899
|
}
|
|
61893
|
-
|
|
61894
|
-
sendChordsForViewport(viewport) {
|
|
61895
|
-
const refFrame = viewport.referenceFrame;
|
|
61896
|
-
const inView = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
61897
|
-
const chords = makeVCFChords(inView);
|
|
61898
|
-
sendChords(chords, this, refFrame, 0.5);
|
|
61899
|
-
}
|
|
61900
61900
|
/**
|
|
61901
61901
|
* Create a "color by" checkbox menu item, optionally initially checked
|
|
61902
61902
|
* @param menuItem
|
|
@@ -62199,7 +62199,7 @@
|
|
|
62199
62199
|
|
|
62200
62200
|
|
|
62201
62201
|
popupData(clickState) {
|
|
62202
|
-
let features = clickState.viewport.
|
|
62202
|
+
let features = clickState.viewport.getCachedFeatures();
|
|
62203
62203
|
if (!features || features.length === 0) return [];
|
|
62204
62204
|
const tolerance = 3;
|
|
62205
62205
|
const tissue = this.name;
|
|
@@ -62545,7 +62545,7 @@
|
|
|
62545
62545
|
popupData(clickState) {
|
|
62546
62546
|
let data = [];
|
|
62547
62547
|
const track = clickState.viewport.trackView.track;
|
|
62548
|
-
const features = clickState.viewport.
|
|
62548
|
+
const features = clickState.viewport.getCachedFeatures();
|
|
62549
62549
|
|
|
62550
62550
|
if (features) {
|
|
62551
62551
|
let count = 0;
|
|
@@ -63234,7 +63234,7 @@
|
|
|
63234
63234
|
if (!this.featureCache) {
|
|
63235
63235
|
const options = buildOptions(this.config);
|
|
63236
63236
|
const data = await igvxhr.loadString(this.config.url, options);
|
|
63237
|
-
this.featureCache = new FeatureCache
|
|
63237
|
+
this.featureCache = new FeatureCache(parseBP(data), genome);
|
|
63238
63238
|
return this.featureCache.queryFeatures(chr, start, end);
|
|
63239
63239
|
} else {
|
|
63240
63240
|
return this.featureCache.queryFeatures(chr, start, end);
|
|
@@ -64477,15 +64477,6 @@
|
|
|
64477
64477
|
this.id = guid$2();
|
|
64478
64478
|
}
|
|
64479
64479
|
|
|
64480
|
-
extend(locus) {
|
|
64481
|
-
const newStart = Math.min(locus.start, this.start);
|
|
64482
|
-
const newEnd = Math.max(locus.end, this.end);
|
|
64483
|
-
const ratio = (newEnd - newStart) / (this.end - this.start);
|
|
64484
|
-
this.start = newStart;
|
|
64485
|
-
this.end = newEnd;
|
|
64486
|
-
this.bpPerPixel *= ratio;
|
|
64487
|
-
}
|
|
64488
|
-
|
|
64489
64480
|
calculateEnd(pixels) {
|
|
64490
64481
|
return this.start + this.bpPerPixel * pixels;
|
|
64491
64482
|
}
|
|
@@ -64570,7 +64561,7 @@
|
|
|
64570
64561
|
const viewChanged = start !== this.start || bpPerPixel !== this.bpPerPixel;
|
|
64571
64562
|
|
|
64572
64563
|
if (viewChanged) {
|
|
64573
|
-
await browser.updateViews(
|
|
64564
|
+
await browser.updateViews(this);
|
|
64574
64565
|
}
|
|
64575
64566
|
}
|
|
64576
64567
|
|
|
@@ -66535,12 +66526,7 @@
|
|
|
66535
66526
|
}
|
|
66536
66527
|
}
|
|
66537
66528
|
|
|
66538
|
-
await this.loadTrackList(trackConfigurations);
|
|
66539
|
-
|
|
66540
|
-
for (let rtv of this.trackViews.filter(tv => tv.track.type === 'ruler')) {
|
|
66541
|
-
rtv.updateViews();
|
|
66542
|
-
}
|
|
66543
|
-
|
|
66529
|
+
await this.loadTrackList(trackConfigurations);
|
|
66544
66530
|
this.updateUIWithReferenceFrameList();
|
|
66545
66531
|
}
|
|
66546
66532
|
|
|
@@ -66705,22 +66691,26 @@
|
|
|
66705
66691
|
}
|
|
66706
66692
|
|
|
66707
66693
|
async loadTrackList(configList) {
|
|
66708
|
-
|
|
66694
|
+
try {
|
|
66695
|
+
const promises = [];
|
|
66709
66696
|
|
|
66710
|
-
|
|
66711
|
-
|
|
66712
|
-
|
|
66697
|
+
for (let config of configList) {
|
|
66698
|
+
promises.push(this.loadTrack(config, false));
|
|
66699
|
+
}
|
|
66713
66700
|
|
|
66714
|
-
|
|
66715
|
-
|
|
66716
|
-
|
|
66717
|
-
|
|
66701
|
+
const loadedTracks = await Promise.all(promises);
|
|
66702
|
+
const groupAutoscaleViews = this.trackViews.filter(function (trackView) {
|
|
66703
|
+
return trackView.track.autoscaleGroup;
|
|
66704
|
+
});
|
|
66718
66705
|
|
|
66719
|
-
|
|
66720
|
-
|
|
66721
|
-
|
|
66706
|
+
if (groupAutoscaleViews.length > 0) {
|
|
66707
|
+
this.updateViews(groupAutoscaleViews);
|
|
66708
|
+
}
|
|
66722
66709
|
|
|
66723
|
-
|
|
66710
|
+
return loadedTracks;
|
|
66711
|
+
} finally {
|
|
66712
|
+
await this.resize();
|
|
66713
|
+
}
|
|
66724
66714
|
}
|
|
66725
66715
|
|
|
66726
66716
|
async loadROI(config) {
|
|
@@ -66734,9 +66724,7 @@
|
|
|
66734
66724
|
}
|
|
66735
66725
|
} else {
|
|
66736
66726
|
this.roi.push(new ROI(config, this.genome));
|
|
66737
|
-
}
|
|
66738
|
-
// rarely called.
|
|
66739
|
-
|
|
66727
|
+
}
|
|
66740
66728
|
|
|
66741
66729
|
await this.updateViews(true);
|
|
66742
66730
|
}
|
|
@@ -66750,7 +66738,7 @@
|
|
|
66750
66738
|
}
|
|
66751
66739
|
|
|
66752
66740
|
for (let tv of this.trackViews) {
|
|
66753
|
-
tv.
|
|
66741
|
+
tv.updateViews(true);
|
|
66754
66742
|
}
|
|
66755
66743
|
}
|
|
66756
66744
|
|
|
@@ -66758,7 +66746,7 @@
|
|
|
66758
66746
|
this.roi = [];
|
|
66759
66747
|
|
|
66760
66748
|
for (let tv of this.trackViews) {
|
|
66761
|
-
tv.
|
|
66749
|
+
tv.updateViews(true);
|
|
66762
66750
|
}
|
|
66763
66751
|
}
|
|
66764
66752
|
|
|
@@ -66774,13 +66762,25 @@
|
|
|
66774
66762
|
/**
|
|
66775
66763
|
* Return a promise to load a track.
|
|
66776
66764
|
*
|
|
66765
|
+
* Each track is associated with the following DOM elements
|
|
66766
|
+
*
|
|
66767
|
+
* leftHandGutter - div on the left for track controls and legend
|
|
66768
|
+
* contentDiv - a div element wrapping all the track content. Height can be > viewportDiv height
|
|
66769
|
+
* viewportDiv - a div element through which the track is viewed. This might have a vertical scrollbar
|
|
66770
|
+
* canvas - canvas element upon which the track is drawn. Child of contentDiv
|
|
66771
|
+
*
|
|
66772
|
+
* The width of all elements should be equal. Height of the viewportDiv is controlled by the user, but never
|
|
66773
|
+
* greater than the contentDiv height. Height of contentDiv and canvas are equal, and governed by the data
|
|
66774
|
+
* loaded.
|
|
66775
|
+
*
|
|
66776
|
+
*
|
|
66777
66777
|
* @param config
|
|
66778
66778
|
* @param doResize - undefined by default
|
|
66779
66779
|
* @returns {*}
|
|
66780
66780
|
*/
|
|
66781
66781
|
|
|
66782
66782
|
|
|
66783
|
-
async loadTrack(config) {
|
|
66783
|
+
async loadTrack(config, doResize) {
|
|
66784
66784
|
// config might be json
|
|
66785
66785
|
if (isString$3(config)) {
|
|
66786
66786
|
config = JSON.parse(config);
|
|
@@ -66845,6 +66845,11 @@
|
|
|
66845
66845
|
|
|
66846
66846
|
msg += ": " + config.url;
|
|
66847
66847
|
Alert.presentAlert(new Error(msg), undefined);
|
|
66848
|
+
} finally {
|
|
66849
|
+
// TODO: If loadTrack() is called individually - not via loadTrackList() - call this.resize()
|
|
66850
|
+
if (false === doResize) ; else {
|
|
66851
|
+
await this.resize();
|
|
66852
|
+
}
|
|
66848
66853
|
}
|
|
66849
66854
|
}
|
|
66850
66855
|
/**
|
|
@@ -67077,7 +67082,40 @@
|
|
|
67077
67082
|
this.navbarManager.navbarDidResize(this.$navigation.width(), isWGV);
|
|
67078
67083
|
}
|
|
67079
67084
|
|
|
67080
|
-
await resize
|
|
67085
|
+
await this.resize();
|
|
67086
|
+
}
|
|
67087
|
+
|
|
67088
|
+
async resize() {
|
|
67089
|
+
const viewportWidth = this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67090
|
+
|
|
67091
|
+
for (let referenceFrame of this.referenceFrameList) {
|
|
67092
|
+
const index = this.referenceFrameList.indexOf(referenceFrame);
|
|
67093
|
+
const {
|
|
67094
|
+
chr,
|
|
67095
|
+
genome
|
|
67096
|
+
} = referenceFrame;
|
|
67097
|
+
const {
|
|
67098
|
+
bpLength
|
|
67099
|
+
} = genome.getChromosome(referenceFrame.chr);
|
|
67100
|
+
const viewportWidthBP = referenceFrame.toBP(viewportWidth); // viewportWidthBP > bpLength occurs when locus is full chromosome and user widens browser
|
|
67101
|
+
|
|
67102
|
+
if (GenomeUtils.isWholeGenomeView(chr) || viewportWidthBP > bpLength) {
|
|
67103
|
+
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) bpp. viewport ${ StringUtils.numberFormatter(viewportWidthBP) } > ${ StringUtils.numberFormatter(bpLength) }.`)
|
|
67104
|
+
referenceFrame.bpPerPixel = bpLength / viewportWidth;
|
|
67105
|
+
} else {
|
|
67106
|
+
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) end.`)
|
|
67107
|
+
referenceFrame.end = referenceFrame.start + referenceFrame.toBP(viewportWidth);
|
|
67108
|
+
}
|
|
67109
|
+
|
|
67110
|
+
for (let {
|
|
67111
|
+
viewports
|
|
67112
|
+
} of this.trackViews) {
|
|
67113
|
+
viewports[index].setWidth(viewportWidth);
|
|
67114
|
+
}
|
|
67115
|
+
}
|
|
67116
|
+
|
|
67117
|
+
await this.updateViews(true);
|
|
67118
|
+
this.updateUIWithReferenceFrameList();
|
|
67081
67119
|
}
|
|
67082
67120
|
|
|
67083
67121
|
async updateViews(force) {
|
|
@@ -67153,12 +67191,6 @@
|
|
|
67153
67191
|
}
|
|
67154
67192
|
}
|
|
67155
67193
|
|
|
67156
|
-
repaintViews() {
|
|
67157
|
-
for (let trackView of this.trackViews) {
|
|
67158
|
-
trackView.repaintViews();
|
|
67159
|
-
}
|
|
67160
|
-
}
|
|
67161
|
-
|
|
67162
67194
|
updateLocusSearchWidget() {
|
|
67163
67195
|
const referenceFrameList = this.referenceFrameList; // Update end position of reference frames based on pixel widths. This is hacky, but its been done here
|
|
67164
67196
|
// for a long time, although indirectly.
|
|
@@ -67250,54 +67282,7 @@
|
|
|
67250
67282
|
}
|
|
67251
67283
|
|
|
67252
67284
|
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
67253
|
-
await resize
|
|
67254
|
-
}
|
|
67255
|
-
/**
|
|
67256
|
-
* Add a new multi-locus panel for the specified region
|
|
67257
|
-
* @param chr
|
|
67258
|
-
* @param start
|
|
67259
|
-
* @param end
|
|
67260
|
-
* @param referenceFrameLeft - optional, if supplied new panel should be placed to the immediate right
|
|
67261
|
-
*/
|
|
67262
|
-
|
|
67263
|
-
|
|
67264
|
-
async addMultiLocusPanel(chr, start, end, referenceFrameLeft) {
|
|
67265
|
-
// account for reduced viewport width as a result of adding right mate pair panel
|
|
67266
|
-
const viewportWidth = this.calculateViewportWidth(1 + this.referenceFrameList.length);
|
|
67267
|
-
const scaleFactor = this.calculateViewportWidth(this.referenceFrameList.length) / this.calculateViewportWidth(1 + this.referenceFrameList.length);
|
|
67268
|
-
|
|
67269
|
-
for (let refFrame of this.referenceFrameList) {
|
|
67270
|
-
refFrame.bpPerPixel *= scaleFactor;
|
|
67271
|
-
}
|
|
67272
|
-
|
|
67273
|
-
const bpp = (end - start) / viewportWidth;
|
|
67274
|
-
const newReferenceFrame = new ReferenceFrame(this.genome, chr, start, end, bpp);
|
|
67275
|
-
const indexLeft = referenceFrameLeft ? this.referenceFrameList.indexOf(referenceFrameLeft) : this.referenceFrameList.length - 1;
|
|
67276
|
-
const indexRight = 1 + indexLeft; // TODO -- this is really ugly
|
|
67277
|
-
|
|
67278
|
-
const {
|
|
67279
|
-
$viewport
|
|
67280
|
-
} = this.trackViews[0].viewports[indexLeft];
|
|
67281
|
-
const viewportColumn = viewportColumnManager.insertAfter($viewport.get(0).parentElement);
|
|
67282
|
-
|
|
67283
|
-
if (indexRight === this.referenceFrameList.length) {
|
|
67284
|
-
this.referenceFrameList.push(newReferenceFrame);
|
|
67285
|
-
|
|
67286
|
-
for (let trackView of this.trackViews) {
|
|
67287
|
-
const viewport = createViewport(trackView, viewportColumn, newReferenceFrame);
|
|
67288
|
-
trackView.viewports.push(viewport);
|
|
67289
|
-
}
|
|
67290
|
-
} else {
|
|
67291
|
-
this.referenceFrameList.splice(indexRight, 0, newReferenceFrame);
|
|
67292
|
-
|
|
67293
|
-
for (let trackView of this.trackViews) {
|
|
67294
|
-
const viewport = createViewport(trackView, viewportColumn, newReferenceFrame);
|
|
67295
|
-
trackView.viewports.splice(indexRight, 0, viewport);
|
|
67296
|
-
}
|
|
67297
|
-
}
|
|
67298
|
-
|
|
67299
|
-
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
67300
|
-
resize.call(this);
|
|
67285
|
+
await this.resize();
|
|
67301
67286
|
}
|
|
67302
67287
|
|
|
67303
67288
|
async removeMultiLocusPanel(referenceFrame) {
|
|
@@ -67326,15 +67311,8 @@
|
|
|
67326
67311
|
const scaleFactor = this.calculateViewportWidth(1 + this.referenceFrameList.length) / this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67327
67312
|
await this.rescaleForMultiLocus(scaleFactor);
|
|
67328
67313
|
}
|
|
67329
|
-
/**
|
|
67330
|
-
* Goto the locus represented by the selected referenceFrame, discarding all other panels
|
|
67331
|
-
*
|
|
67332
|
-
* @param referenceFrame
|
|
67333
|
-
* @returns {Promise<void>}
|
|
67334
|
-
*/
|
|
67335
67314
|
|
|
67336
|
-
|
|
67337
|
-
async gotoMultilocusPanel(referenceFrame) {
|
|
67315
|
+
async selectMultiLocusPanel(referenceFrame) {
|
|
67338
67316
|
const referenceFrameIndex = this.referenceFrameList.indexOf(referenceFrame); // Remove columns for unselected panels
|
|
67339
67317
|
|
|
67340
67318
|
this.columnContainer.querySelectorAll('.igv-column').forEach((column, c) => {
|
|
@@ -67382,7 +67360,7 @@
|
|
|
67382
67360
|
|
|
67383
67361
|
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
67384
67362
|
this.updateUIWithReferenceFrameList();
|
|
67385
|
-
await this.updateViews();
|
|
67363
|
+
await this.updateViews(true);
|
|
67386
67364
|
}
|
|
67387
67365
|
/**
|
|
67388
67366
|
* @deprecated This is a deprecated method with no known usages. To be removed in a future release.
|
|
@@ -67636,9 +67614,18 @@
|
|
|
67636
67614
|
return surl;
|
|
67637
67615
|
}
|
|
67638
67616
|
|
|
67639
|
-
|
|
67617
|
+
currentLoci() {
|
|
67618
|
+
const loci = [];
|
|
67640
67619
|
const anyTrackView = this.trackViews[0];
|
|
67641
|
-
|
|
67620
|
+
|
|
67621
|
+
for (let {
|
|
67622
|
+
referenceFrame
|
|
67623
|
+
} of anyTrackView.viewports) {
|
|
67624
|
+
const locusString = referenceFrame.getLocusString();
|
|
67625
|
+
loci.push(locusString);
|
|
67626
|
+
}
|
|
67627
|
+
|
|
67628
|
+
return loci;
|
|
67642
67629
|
}
|
|
67643
67630
|
/**
|
|
67644
67631
|
* Record a mouse click on a specific viewport. This might be the start of a drag operation. Dragging
|
|
@@ -67751,9 +67738,12 @@
|
|
|
67751
67738
|
}
|
|
67752
67739
|
|
|
67753
67740
|
addWindowResizeHandler() {
|
|
67754
|
-
|
|
67755
|
-
this.boundWindowResizeHandler = resize.bind(this);
|
|
67741
|
+
this.boundWindowResizeHandler = windowResizeHandler.bind(this);
|
|
67756
67742
|
window.addEventListener('resize', this.boundWindowResizeHandler);
|
|
67743
|
+
|
|
67744
|
+
function windowResizeHandler() {
|
|
67745
|
+
this.resize();
|
|
67746
|
+
}
|
|
67757
67747
|
}
|
|
67758
67748
|
|
|
67759
67749
|
removeWindowResizeHandler() {
|
|
@@ -67847,47 +67837,6 @@
|
|
|
67847
67837
|
}
|
|
67848
67838
|
|
|
67849
67839
|
}
|
|
67850
|
-
/**
|
|
67851
|
-
* Function called win window is resized, or visibility changed (e.g. "show" from a tab). This is a function rather
|
|
67852
|
-
* than class method because it needs to be copied and bound to specific instances of browser to support listener
|
|
67853
|
-
* removal
|
|
67854
|
-
*
|
|
67855
|
-
* @returns {Promise<void>}
|
|
67856
|
-
*/
|
|
67857
|
-
|
|
67858
|
-
|
|
67859
|
-
async function resize() {
|
|
67860
|
-
const viewportWidth = this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67861
|
-
|
|
67862
|
-
for (let referenceFrame of this.referenceFrameList) {
|
|
67863
|
-
const index = this.referenceFrameList.indexOf(referenceFrame);
|
|
67864
|
-
const {
|
|
67865
|
-
chr,
|
|
67866
|
-
genome
|
|
67867
|
-
} = referenceFrame;
|
|
67868
|
-
const {
|
|
67869
|
-
bpLength
|
|
67870
|
-
} = genome.getChromosome(referenceFrame.chr);
|
|
67871
|
-
const viewportWidthBP = referenceFrame.toBP(viewportWidth); // viewportWidthBP > bpLength occurs when locus is full chromosome and user widens browser
|
|
67872
|
-
|
|
67873
|
-
if (GenomeUtils.isWholeGenomeView(chr) || viewportWidthBP > bpLength) {
|
|
67874
|
-
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) bpp. viewport ${ StringUtils.numberFormatter(viewportWidthBP) } > ${ StringUtils.numberFormatter(bpLength) }.`)
|
|
67875
|
-
referenceFrame.bpPerPixel = bpLength / viewportWidth;
|
|
67876
|
-
} else {
|
|
67877
|
-
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) end.`)
|
|
67878
|
-
referenceFrame.end = referenceFrame.start + referenceFrame.toBP(viewportWidth);
|
|
67879
|
-
}
|
|
67880
|
-
|
|
67881
|
-
for (let {
|
|
67882
|
-
viewports
|
|
67883
|
-
} of this.trackViews) {
|
|
67884
|
-
viewports[index].setWidth(viewportWidth);
|
|
67885
|
-
}
|
|
67886
|
-
}
|
|
67887
|
-
|
|
67888
|
-
this.updateUIWithReferenceFrameList();
|
|
67889
|
-
await this.updateViews(true);
|
|
67890
|
-
}
|
|
67891
67840
|
|
|
67892
67841
|
function handleMouseMove(e) {
|
|
67893
67842
|
e.preventDefault();
|