igv 2.12.0 → 2.12.3
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 -10
- package/dist/igv.esm.js +289 -167
- package/dist/igv.esm.min.js +4 -4
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +345 -187
- package/dist/igv.min.js +7 -7
- package/dist/igv.min.js.map +1 -1
- package/package.json +2 -2
package/dist/igv.esm.js
CHANGED
|
@@ -19712,6 +19712,8 @@ const knownFileExtensions = new Set([
|
|
|
19712
19712
|
"bb",
|
|
19713
19713
|
"bigbed",
|
|
19714
19714
|
"biginteract",
|
|
19715
|
+
"biggenepred",
|
|
19716
|
+
"bignarrowpeak",
|
|
19715
19717
|
"bw",
|
|
19716
19718
|
"bigwig",
|
|
19717
19719
|
"bam",
|
|
@@ -19863,6 +19865,8 @@ function inferTrackType(config) {
|
|
|
19863
19865
|
case "bed":
|
|
19864
19866
|
case "bigbed":
|
|
19865
19867
|
case "bb":
|
|
19868
|
+
case "biggenepred":
|
|
19869
|
+
case "bignarrowpeak":
|
|
19866
19870
|
return "bedtype"
|
|
19867
19871
|
default:
|
|
19868
19872
|
return "annotation"
|
|
@@ -20247,6 +20251,12 @@ for (let i = 0; i < t1.length; i++) {
|
|
|
20247
20251
|
complement[t1[i].toLowerCase()] = t2[i].toLowerCase();
|
|
20248
20252
|
}
|
|
20249
20253
|
|
|
20254
|
+
const DEFAULT_HEIGHT = 25;
|
|
20255
|
+
const TRANSLATED_HEIGHT = 115;
|
|
20256
|
+
const SEQUENCE_HEIGHT = 15;
|
|
20257
|
+
const FRAME_HEIGHT = 25;
|
|
20258
|
+
const FRAME_BORDER = 5;
|
|
20259
|
+
|
|
20250
20260
|
class SequenceTrack {
|
|
20251
20261
|
|
|
20252
20262
|
constructor(config, browser) {
|
|
@@ -20258,13 +20268,13 @@ class SequenceTrack {
|
|
|
20258
20268
|
this.name = "Sequence";
|
|
20259
20269
|
this.id = "sequence";
|
|
20260
20270
|
this.sequenceType = config.sequenceType || "dna"; // dna | rna | prot
|
|
20261
|
-
this.height = 25;
|
|
20262
20271
|
this.disableButtons = false;
|
|
20263
20272
|
this.order = config.order || defaultSequenceTrackOrder;
|
|
20264
20273
|
this.ignoreTrackMenu = false;
|
|
20265
20274
|
|
|
20266
|
-
this.reversed =
|
|
20267
|
-
this.frameTranslate =
|
|
20275
|
+
this.reversed = config.reversed === true;
|
|
20276
|
+
this.frameTranslate = config.frameTranslate === true;
|
|
20277
|
+
this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
|
|
20268
20278
|
|
|
20269
20279
|
}
|
|
20270
20280
|
|
|
@@ -20283,14 +20293,14 @@ class SequenceTrack {
|
|
|
20283
20293
|
this.frameTranslate = !this.frameTranslate;
|
|
20284
20294
|
if (this.frameTranslate) {
|
|
20285
20295
|
for (let vp of this.trackView.viewports) {
|
|
20286
|
-
vp.setContentHeight(
|
|
20296
|
+
vp.setContentHeight(TRANSLATED_HEIGHT);
|
|
20287
20297
|
}
|
|
20288
|
-
this.trackView.setTrackHeight(
|
|
20298
|
+
this.trackView.setTrackHeight(TRANSLATED_HEIGHT);
|
|
20289
20299
|
} else {
|
|
20290
20300
|
for (let vp of this.trackView.viewports) {
|
|
20291
|
-
vp.setContentHeight(
|
|
20301
|
+
vp.setContentHeight(DEFAULT_HEIGHT);
|
|
20292
20302
|
}
|
|
20293
|
-
this.trackView.setTrackHeight(
|
|
20303
|
+
this.trackView.setTrackHeight(DEFAULT_HEIGHT);
|
|
20294
20304
|
}
|
|
20295
20305
|
this.trackView.repaintViews();
|
|
20296
20306
|
|
|
@@ -20373,7 +20383,8 @@ class SequenceTrack {
|
|
|
20373
20383
|
}
|
|
20374
20384
|
|
|
20375
20385
|
async getFeatures(chr, start, end, bpPerPixel) {
|
|
20376
|
-
|
|
20386
|
+
start = Math.floor(start);
|
|
20387
|
+
end = Math.floor(end);
|
|
20377
20388
|
if (bpPerPixel && bpPerPixel > 1) {
|
|
20378
20389
|
return null
|
|
20379
20390
|
} else {
|
|
@@ -20391,89 +20402,79 @@ class SequenceTrack {
|
|
|
20391
20402
|
|
|
20392
20403
|
if (options.features) {
|
|
20393
20404
|
|
|
20394
|
-
|
|
20395
|
-
const sequenceBpStart = options.features.bpStart;
|
|
20396
|
-
const bpEnd = 1 + options.bpStart + (options.pixelWidth * options.bpPerPixel);
|
|
20405
|
+
let sequence = options.features.sequence;
|
|
20397
20406
|
|
|
20398
|
-
|
|
20399
|
-
|
|
20400
|
-
|
|
20401
|
-
|
|
20407
|
+
if (this.reversed) {
|
|
20408
|
+
sequence = sequence.split('').map(function (cv) {
|
|
20409
|
+
return complement[cv]
|
|
20410
|
+
}).join('');
|
|
20411
|
+
}
|
|
20402
20412
|
|
|
20403
|
-
|
|
20404
|
-
|
|
20413
|
+
const sequenceBpStart = options.features.bpStart; // genomic position at start of sequence
|
|
20414
|
+
const bpEnd = 1 + options.bpStart + (options.pixelWidth * options.bpPerPixel);
|
|
20405
20415
|
|
|
20406
|
-
|
|
20407
|
-
letter = complement[letter] || "";
|
|
20408
|
-
}
|
|
20416
|
+
for (let bp = Math.floor(options.bpStart); bp <= bpEnd; bp++) {
|
|
20409
20417
|
|
|
20410
|
-
|
|
20411
|
-
let aPixel = offsetBP / options.bpPerPixel;
|
|
20412
|
-
let bPixel = (offsetBP + 1) / options.bpPerPixel;
|
|
20413
|
-
let color = this.fillColor(letter);
|
|
20418
|
+
const seqIdx = Math.floor(bp - sequenceBpStart);
|
|
20414
20419
|
|
|
20415
|
-
|
|
20420
|
+
if (seqIdx >= 0 && seqIdx < sequence.length) {
|
|
20421
|
+
const baseLetter = sequence[seqIdx];
|
|
20422
|
+
const offsetBP = bp - options.bpStart;
|
|
20423
|
+
const aPixel = offsetBP / options.bpPerPixel;
|
|
20424
|
+
const pixelWidth = 1 / options.bpPerPixel;
|
|
20425
|
+
const color = this.fillColor(baseLetter);
|
|
20416
20426
|
|
|
20417
20427
|
if (options.bpPerPixel > 1 / 10) {
|
|
20418
|
-
IGVGraphics.fillRect(ctx, aPixel, 5,
|
|
20428
|
+
IGVGraphics.fillRect(ctx, aPixel, 5, pixelWidth, SEQUENCE_HEIGHT - 5, {fillStyle: color});
|
|
20419
20429
|
} else {
|
|
20420
|
-
let
|
|
20421
|
-
IGVGraphics.strokeText(ctx,
|
|
20430
|
+
let textPixel = aPixel + 0.5 * (pixelWidth - ctx.measureText(baseLetter).width);
|
|
20431
|
+
IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {strokeStyle: color});
|
|
20422
20432
|
}
|
|
20423
20433
|
}
|
|
20424
20434
|
}
|
|
20425
20435
|
|
|
20426
20436
|
if (this.frameTranslate) {
|
|
20427
20437
|
|
|
20428
|
-
let
|
|
20429
|
-
|
|
20430
|
-
transSeq = sequence.split('').map(function (cv) {
|
|
20431
|
-
return complement[cv]
|
|
20432
|
-
});
|
|
20433
|
-
transSeq = transSeq.join('');
|
|
20434
|
-
} else {
|
|
20435
|
-
transSeq = sequence;
|
|
20436
|
-
}
|
|
20438
|
+
let y = SEQUENCE_HEIGHT + 2 * FRAME_BORDER;
|
|
20439
|
+
const translatedSequence = this.translateSequence(sequence);
|
|
20437
20440
|
|
|
20438
|
-
let
|
|
20439
|
-
let translatedSequence = this.translateSequence(transSeq);
|
|
20440
|
-
for (let arr of translatedSequence) {
|
|
20441
|
+
for (let fNum = 0; fNum < translatedSequence.length; fNum++) { // == 3, 1 for each frame
|
|
20441
20442
|
|
|
20442
|
-
|
|
20443
|
-
let fNum = i;
|
|
20444
|
-
let h = 25;
|
|
20443
|
+
const aaSequence = translatedSequence[fNum]; // AA sequence for this frame
|
|
20445
20444
|
|
|
20446
|
-
|
|
20445
|
+
for (let idx = 0; idx < aaSequence.length; idx++) {
|
|
20447
20446
|
|
|
20448
|
-
for (let cv of arr) {
|
|
20449
|
-
|
|
20450
|
-
let aaS;
|
|
20451
|
-
let idx = arr.indexOf(cv);
|
|
20452
|
-
let xSeed = (idx + fNum) + (2 * idx);
|
|
20453
20447
|
let color = 0 === idx % 2 ? 'rgb(160,160,160)' : 'rgb(224,224,224)';
|
|
20448
|
+
const cv = aaSequence[idx];
|
|
20449
|
+
|
|
20450
|
+
const bpPos = sequenceBpStart + fNum + (idx * 3);
|
|
20451
|
+
const bpOffset = bpPos - options.bpStart;
|
|
20452
|
+
const p0 = Math.floor(bpOffset / options.bpPerPixel);
|
|
20453
|
+
const p1 = Math.floor((bpOffset + 3) / options.bpPerPixel);
|
|
20454
|
+
const pc = Math.round((p0 + p1) / 2);
|
|
20455
|
+
|
|
20456
|
+
if (p1 < 0) {
|
|
20457
|
+
continue // off left edge
|
|
20458
|
+
} else if (p0 > options.pixelWidth) {
|
|
20459
|
+
break // off right edge
|
|
20460
|
+
}
|
|
20454
20461
|
|
|
20455
|
-
let
|
|
20456
|
-
let p1 = Math.floor((xSeed + 3) / options.bpPerPixel);
|
|
20457
|
-
let pc = Math.round((p0 + p1) / 2);
|
|
20458
|
-
|
|
20462
|
+
let aaLabel = cv.aminoA;
|
|
20459
20463
|
if (cv.aminoA.indexOf('STOP') > -1) {
|
|
20460
20464
|
color = 'rgb(255, 0, 0)';
|
|
20461
|
-
|
|
20462
|
-
} else {
|
|
20463
|
-
aaS = cv.aminoA;
|
|
20464
|
-
}
|
|
20465
|
-
|
|
20466
|
-
if (cv.aminoA === 'M') {
|
|
20465
|
+
aaLabel = 'STOP'; //Color blind accessible
|
|
20466
|
+
} else if (cv.aminoA === 'M') {
|
|
20467
20467
|
color = 'rgb(0, 153, 0)';
|
|
20468
|
-
|
|
20468
|
+
aaLabel = 'START'; //Color blind accessible
|
|
20469
20469
|
}
|
|
20470
20470
|
|
|
20471
|
-
IGVGraphics.fillRect(ctx, p0, y, p1 - p0,
|
|
20471
|
+
IGVGraphics.fillRect(ctx, p0, y, p1 - p0, FRAME_HEIGHT, {fillStyle: color});
|
|
20472
20472
|
|
|
20473
20473
|
if (options.bpPerPixel <= 1 / 10) {
|
|
20474
|
-
IGVGraphics.strokeText(ctx,
|
|
20474
|
+
IGVGraphics.strokeText(ctx, aaLabel, pc - (ctx.measureText(aaLabel).width / 2), y + 15);
|
|
20475
20475
|
}
|
|
20476
20476
|
}
|
|
20477
|
+
y += (FRAME_HEIGHT + FRAME_BORDER);
|
|
20477
20478
|
}
|
|
20478
20479
|
}
|
|
20479
20480
|
}
|
|
@@ -20484,6 +20485,7 @@ class SequenceTrack {
|
|
|
20484
20485
|
}
|
|
20485
20486
|
|
|
20486
20487
|
computePixelHeight(ignore) {
|
|
20488
|
+
this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
|
|
20487
20489
|
return this.height
|
|
20488
20490
|
}
|
|
20489
20491
|
|
|
@@ -20496,8 +20498,21 @@ class SequenceTrack {
|
|
|
20496
20498
|
} else {
|
|
20497
20499
|
return 'rgb(0, 0, 150)'
|
|
20498
20500
|
}
|
|
20501
|
+
}
|
|
20499
20502
|
|
|
20503
|
+
/**
|
|
20504
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
20505
|
+
*
|
|
20506
|
+
* @returns {*|{}}
|
|
20507
|
+
*/
|
|
20508
|
+
getState() {
|
|
20509
|
+
|
|
20510
|
+
const config = typeof super.getState === 'function' ? super.getState() : {};
|
|
20511
|
+
if (this.reversed) config.revealed = true;
|
|
20512
|
+
if (this.frameTranslate) config.frameTranslate = true;
|
|
20513
|
+
return config
|
|
20500
20514
|
}
|
|
20515
|
+
|
|
20501
20516
|
}
|
|
20502
20517
|
|
|
20503
20518
|
/*
|
|
@@ -22333,7 +22348,9 @@ class FastaSequence {
|
|
|
22333
22348
|
|
|
22334
22349
|
async getSequence(chr, start, end) {
|
|
22335
22350
|
|
|
22336
|
-
|
|
22351
|
+
const hasCachedSquence = this.interval && this.interval.contains(chr, start, end);
|
|
22352
|
+
|
|
22353
|
+
if (!hasCachedSquence) {
|
|
22337
22354
|
|
|
22338
22355
|
// Expand query, to minimum of 50kb
|
|
22339
22356
|
let qstart = start;
|
|
@@ -22792,7 +22809,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
22792
22809
|
}
|
|
22793
22810
|
};
|
|
22794
22811
|
|
|
22795
|
-
const _version = "2.12.
|
|
22812
|
+
const _version = "2.12.3";
|
|
22796
22813
|
function version() {
|
|
22797
22814
|
return _version
|
|
22798
22815
|
}
|
|
@@ -22940,7 +22957,7 @@ class Genome {
|
|
|
22940
22957
|
constructor(config, sequence, ideograms, aliases) {
|
|
22941
22958
|
|
|
22942
22959
|
this.config = config;
|
|
22943
|
-
this.id = config.id;
|
|
22960
|
+
this.id = config.id || generateGenomeID(config);
|
|
22944
22961
|
this.sequence = sequence;
|
|
22945
22962
|
this.chromosomeNames = sequence.chromosomeNames;
|
|
22946
22963
|
this.chromosomes = sequence.chromosomes; // An object (functions as a dictionary)
|
|
@@ -23262,6 +23279,18 @@ function constructWG(genome, config) {
|
|
|
23262
23279
|
|
|
23263
23280
|
}
|
|
23264
23281
|
|
|
23282
|
+
function generateGenomeID(config) {
|
|
23283
|
+
if (config.id !== undefined) {
|
|
23284
|
+
return config.id
|
|
23285
|
+
} else if (config.fastaURL && isString$3(config.fastaURL)) {
|
|
23286
|
+
return config.fastaURL
|
|
23287
|
+
} else if (config.fastaURL && config.fastaURL.name) {
|
|
23288
|
+
return config.fastaURL.name
|
|
23289
|
+
} else {
|
|
23290
|
+
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
|
|
23291
|
+
}
|
|
23292
|
+
}
|
|
23293
|
+
|
|
23265
23294
|
/**
|
|
23266
23295
|
* Created by dat on 9/16/16.
|
|
23267
23296
|
*/
|
|
@@ -23444,6 +23473,17 @@ class TrackViewport extends Viewport {
|
|
|
23444
23473
|
}
|
|
23445
23474
|
}
|
|
23446
23475
|
|
|
23476
|
+
repaintDimensions() {
|
|
23477
|
+
const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
|
|
23478
|
+
const pixelWidth = isWGV ? this.$viewport.width() : 3 * this.$viewport.width();
|
|
23479
|
+
const bpPerPixel = this.referenceFrame.bpPerPixel;
|
|
23480
|
+
const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
|
|
23481
|
+
const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
|
|
23482
|
+
return {
|
|
23483
|
+
startBP, endBP, pixelWidth
|
|
23484
|
+
}
|
|
23485
|
+
}
|
|
23486
|
+
|
|
23447
23487
|
/**
|
|
23448
23488
|
* Repaint the canvas using the cached features
|
|
23449
23489
|
*
|
|
@@ -23458,11 +23498,11 @@ class TrackViewport extends Viewport {
|
|
|
23458
23498
|
//this.tile.bpPerPixel = this.referenceFrame.bpPerPixel
|
|
23459
23499
|
|
|
23460
23500
|
// const isWGV = GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr)
|
|
23461
|
-
|
|
23501
|
+
GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
|
|
23462
23502
|
|
|
23463
23503
|
// Canvas dimensions. There is no left-right panning for WGV so canvas width is viewport width.
|
|
23464
23504
|
// For deep tracks we paint a canvas == 3*viewportHeight centered on the current vertical scroll position
|
|
23465
|
-
const pixelWidth =
|
|
23505
|
+
const {startBP, endBP, pixelWidth} = this.repaintDimensions();
|
|
23466
23506
|
const viewportHeight = this.$viewport.height();
|
|
23467
23507
|
const contentHeight = this.getContentHeight();
|
|
23468
23508
|
const minHeight = roiFeatures ? Math.max(contentHeight, viewportHeight) : contentHeight; // Need to fill viewport for ROIs.
|
|
@@ -23476,8 +23516,8 @@ class TrackViewport extends Viewport {
|
|
|
23476
23516
|
const canvasTop = Math.max(0, -(this.$content.position().top) - viewportHeight);
|
|
23477
23517
|
|
|
23478
23518
|
const bpPerPixel = this.referenceFrame.bpPerPixel;
|
|
23479
|
-
const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
|
|
23480
|
-
const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
|
|
23519
|
+
//const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
|
|
23520
|
+
//const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
|
|
23481
23521
|
const pixelXOffset = Math.round((startBP - this.referenceFrame.start) / bpPerPixel);
|
|
23482
23522
|
|
|
23483
23523
|
const newCanvas = $$1('<canvas class="igv-canvas">').get(0);
|
|
@@ -23740,10 +23780,9 @@ class TrackViewport extends Viewport {
|
|
|
23740
23780
|
if (!this.featureCache) return true
|
|
23741
23781
|
const referenceFrame = this.referenceFrame;
|
|
23742
23782
|
const chr = this.referenceFrame.chr;
|
|
23743
|
-
const start = referenceFrame.start;
|
|
23744
|
-
const end = start + referenceFrame.toBP($$1(this.contentDiv).width());
|
|
23745
23783
|
const bpPerPixel = referenceFrame.bpPerPixel;
|
|
23746
|
-
|
|
23784
|
+
const {startBP, endBP} = this.repaintDimensions();
|
|
23785
|
+
return (!this.featureCache.containsRange(chr, startBP, endBP, bpPerPixel))
|
|
23747
23786
|
}
|
|
23748
23787
|
|
|
23749
23788
|
createZoomInNotice($parent) {
|
|
@@ -23847,7 +23886,7 @@ class TrackViewport extends Viewport {
|
|
|
23847
23886
|
|
|
23848
23887
|
viewport.addEventListener('click', (event) => {
|
|
23849
23888
|
|
|
23850
|
-
if (this.enableClick) {
|
|
23889
|
+
if (this.enableClick && this.canvas) {
|
|
23851
23890
|
if (3 === event.which || event.ctrlKey) {
|
|
23852
23891
|
return
|
|
23853
23892
|
}
|
|
@@ -24381,6 +24420,10 @@ class PairedAlignment {
|
|
|
24381
24420
|
return this.firstAlignment.mate.strand // Assumption is mate is first-of-pair
|
|
24382
24421
|
}
|
|
24383
24422
|
}
|
|
24423
|
+
|
|
24424
|
+
hasTag(str) {
|
|
24425
|
+
return this.firstAlignment.hasTag(str) || (this.secondAlignment && this.secondAlignment.hasTag(str))
|
|
24426
|
+
}
|
|
24384
24427
|
}
|
|
24385
24428
|
|
|
24386
24429
|
/*
|
|
@@ -29004,6 +29047,10 @@ class BamSource {
|
|
|
29004
29047
|
* THE SOFTWARE.
|
|
29005
29048
|
*/
|
|
29006
29049
|
|
|
29050
|
+
const fixColor = (colorString) => {
|
|
29051
|
+
return (colorString.indexOf(",") > 0 && !colorString.startsWith("rgb")) ?
|
|
29052
|
+
`rgb(${colorString})` : colorString
|
|
29053
|
+
};
|
|
29007
29054
|
|
|
29008
29055
|
/**
|
|
29009
29056
|
* A collection of properties and methods shared by all (or most) track types.
|
|
@@ -29048,8 +29095,8 @@ class TrackBase {
|
|
|
29048
29095
|
|
|
29049
29096
|
this.order = config.order;
|
|
29050
29097
|
|
|
29051
|
-
this.color = config.color;
|
|
29052
|
-
this.altColor = config.altColor;
|
|
29098
|
+
if(config.color) this.color = fixColor(config.color);
|
|
29099
|
+
if(config.altColor) this.altColor = fixColor(config.altColor);
|
|
29053
29100
|
if ("civic-ws" === config.sourceType) { // Ugly proxy for specialized track type
|
|
29054
29101
|
this.defaultColor = "rgb(155,20,20)";
|
|
29055
29102
|
} else {
|
|
@@ -30944,7 +30991,7 @@ class ChordSetManager {
|
|
|
30944
30991
|
return this.tracks.find(t => name === t.name)
|
|
30945
30992
|
}
|
|
30946
30993
|
|
|
30947
|
-
|
|
30994
|
+
getChordSet(name) {
|
|
30948
30995
|
return this.chordSets.find(cs => name === cs.name)
|
|
30949
30996
|
}
|
|
30950
30997
|
|
|
@@ -31062,9 +31109,8 @@ class CircularView {
|
|
|
31062
31109
|
buttonContainer.appendChild(this.showControlsButton);
|
|
31063
31110
|
this.showControlsButton.innerText = 'none' === this.controlPanel.style.display ? 'Show Controls' : 'Hide Controls';
|
|
31064
31111
|
this.showControlsButton.addEventListener('click', (event) => {
|
|
31065
|
-
const
|
|
31066
|
-
if (
|
|
31067
|
-
|
|
31112
|
+
const panelRows = this.controlPanel.querySelectorAll('div');
|
|
31113
|
+
if (panelRows.length > 0) {
|
|
31068
31114
|
if ('none' === this.controlPanel.style.display) {
|
|
31069
31115
|
this.controlPanel.style.display = 'flex';
|
|
31070
31116
|
event.target.innerText = 'Hide Controls';
|
|
@@ -31148,10 +31194,10 @@ class CircularView {
|
|
|
31148
31194
|
hideShowButton.innerText = true === chordSet.visible ? 'Hide' : 'Show';
|
|
31149
31195
|
hideShowButton.addEventListener('click', event => {
|
|
31150
31196
|
if (true === chordSet.visible) {
|
|
31151
|
-
this.
|
|
31197
|
+
this.hideChordSet(chordSet.name);
|
|
31152
31198
|
event.target.innerText = "Show";
|
|
31153
31199
|
} else {
|
|
31154
|
-
this.
|
|
31200
|
+
this.showChordSet(chordSet.name);
|
|
31155
31201
|
event.target.innerText = "Hide";
|
|
31156
31202
|
}
|
|
31157
31203
|
});
|
|
@@ -31175,7 +31221,7 @@ class CircularView {
|
|
|
31175
31221
|
color: chordSet.color,
|
|
31176
31222
|
onChange: ({rgbaString}) => {
|
|
31177
31223
|
colorPickerButton.style.backgroundColor = setAlpha(rgbaString, 1);
|
|
31178
|
-
this.
|
|
31224
|
+
this.setColor(chordSet.name, rgbaString);
|
|
31179
31225
|
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
31180
31226
|
}
|
|
31181
31227
|
};
|
|
@@ -31193,7 +31239,7 @@ class CircularView {
|
|
|
31193
31239
|
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
31194
31240
|
alphaSlider.oninput = () => {
|
|
31195
31241
|
const v = valueToAlpha(alphaSlider.value);
|
|
31196
|
-
this.
|
|
31242
|
+
this.setColor(chordSet.name, setAlpha(chordSet.color, v));
|
|
31197
31243
|
picker.setColor(chordSet.color);
|
|
31198
31244
|
};
|
|
31199
31245
|
row.appendChild(alphaSlider);
|
|
@@ -31213,11 +31259,13 @@ class CircularView {
|
|
|
31213
31259
|
*/
|
|
31214
31260
|
setAssembly(igvGenome) {
|
|
31215
31261
|
|
|
31216
|
-
|
|
31262
|
+
const id = this.genomeId || guid();
|
|
31263
|
+
|
|
31264
|
+
if (this.genomeId === id) {
|
|
31217
31265
|
return
|
|
31218
31266
|
}
|
|
31219
31267
|
this.chordManager.clearChords();
|
|
31220
|
-
this.genomeId =
|
|
31268
|
+
this.genomeId = id;
|
|
31221
31269
|
this.chrNames = new Set(igvGenome.chromosomes.map(chr => shortChrName$1(chr.name)));
|
|
31222
31270
|
|
|
31223
31271
|
const regions = [];
|
|
@@ -31238,7 +31286,7 @@ class CircularView {
|
|
|
31238
31286
|
this.assembly = {
|
|
31239
31287
|
name: igvGenome.name,
|
|
31240
31288
|
sequence: {
|
|
31241
|
-
trackId:
|
|
31289
|
+
trackId: id,
|
|
31242
31290
|
type: 'ReferenceSequenceTrack',
|
|
31243
31291
|
adapter: {
|
|
31244
31292
|
type: 'FromConfigSequenceAdapter',
|
|
@@ -31279,7 +31327,7 @@ class CircularView {
|
|
|
31279
31327
|
|
|
31280
31328
|
addChords(newChords, options = {}) {
|
|
31281
31329
|
|
|
31282
|
-
const tmp = options.
|
|
31330
|
+
const tmp = options.name || options.track || "*";
|
|
31283
31331
|
const trackName = tmp.split(' ')[0].replaceAll("%20", " ");
|
|
31284
31332
|
const chordSetName = tmp.replaceAll("%20", " ");
|
|
31285
31333
|
|
|
@@ -31332,21 +31380,6 @@ class CircularView {
|
|
|
31332
31380
|
this.viewState.pluginManager.rootModel.session.clearSelection();
|
|
31333
31381
|
}
|
|
31334
31382
|
|
|
31335
|
-
getFeature(featureId) {
|
|
31336
|
-
|
|
31337
|
-
// TODO -- broken
|
|
31338
|
-
// const display = this.viewState.pluginManager.rootModel.session.view.tracks[0].displays[0]
|
|
31339
|
-
// const feature = display.data.features.get(featureId)
|
|
31340
|
-
// return feature;
|
|
31341
|
-
|
|
31342
|
-
const features = [...this.viewState.config.tracks[0].adapter.features.value];
|
|
31343
|
-
for (let f of features) {
|
|
31344
|
-
if (featureId === f.uniqueId) {
|
|
31345
|
-
return f
|
|
31346
|
-
}
|
|
31347
|
-
}
|
|
31348
|
-
}
|
|
31349
|
-
|
|
31350
31383
|
/**
|
|
31351
31384
|
* Deprecated, use "visible" property
|
|
31352
31385
|
*/
|
|
@@ -31369,23 +31402,23 @@ class CircularView {
|
|
|
31369
31402
|
this.parent.style.display = isVisible ? 'block' : 'none';
|
|
31370
31403
|
}
|
|
31371
31404
|
|
|
31372
|
-
|
|
31373
|
-
let
|
|
31374
|
-
if (
|
|
31375
|
-
|
|
31405
|
+
hideChordSet(trackName) {
|
|
31406
|
+
let cs = this.getChordSet(trackName);
|
|
31407
|
+
if (cs) {
|
|
31408
|
+
cs.visible = false;
|
|
31376
31409
|
this.render();
|
|
31377
31410
|
} else {
|
|
31378
31411
|
console.warn(`No track with name: ${name}`);
|
|
31379
31412
|
}
|
|
31380
31413
|
}
|
|
31381
31414
|
|
|
31382
|
-
|
|
31383
|
-
let
|
|
31384
|
-
if (
|
|
31385
|
-
|
|
31415
|
+
showChordSet(name) {
|
|
31416
|
+
let cs = this.getChordSet(name);
|
|
31417
|
+
if (cs) {
|
|
31418
|
+
cs.visible = true;
|
|
31386
31419
|
this.render();
|
|
31387
31420
|
} else {
|
|
31388
|
-
console.warn(`No track with name: ${
|
|
31421
|
+
console.warn(`No track with name: ${name}`);
|
|
31389
31422
|
}
|
|
31390
31423
|
}
|
|
31391
31424
|
|
|
@@ -31411,12 +31444,12 @@ class CircularView {
|
|
|
31411
31444
|
this.render();
|
|
31412
31445
|
}
|
|
31413
31446
|
|
|
31414
|
-
|
|
31415
|
-
return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.
|
|
31447
|
+
getChordSet(name) {
|
|
31448
|
+
return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.getChordSet(name)
|
|
31416
31449
|
}
|
|
31417
31450
|
|
|
31418
|
-
|
|
31419
|
-
const t = this.
|
|
31451
|
+
setColor(name, color) {
|
|
31452
|
+
const t = this.getChordSet(name);
|
|
31420
31453
|
if (t) {
|
|
31421
31454
|
t.color = color;
|
|
31422
31455
|
const trackID = t.id;
|
|
@@ -31443,8 +31476,6 @@ class CircularView {
|
|
|
31443
31476
|
// Remove all children from possible previous renders. React might do this for us when we render, but just in case.
|
|
31444
31477
|
ReactDOM.unmountComponentAtNode(this.container);
|
|
31445
31478
|
|
|
31446
|
-
|
|
31447
|
-
|
|
31448
31479
|
const visibleChordSets =
|
|
31449
31480
|
(this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets).filter(t => t.visible);
|
|
31450
31481
|
|
|
@@ -31523,7 +31554,7 @@ function guid() {
|
|
|
31523
31554
|
|
|
31524
31555
|
function embedCSS$1() {
|
|
31525
31556
|
|
|
31526
|
-
const css = '.igv-circview-container {\n z-index: 2048;\n
|
|
31557
|
+
const css = '.igv-circview-container {\n z-index: 2048;\n width: fit-content;\n height: fit-content;\n box-sizing: content-box;\n color: dimgray;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n background-color: white;\n border-color: dimgray;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-circview-toolbar {\n position: relative;\n width: 100%;\n height: 32px;\n background-color: lightgrey;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n\n.igv-circview-toolbar-button-container {\n height: 100%;\n width: fit-content;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-toolbar-button-container > div {\n margin: 4px;\n}\n\n.igv-circview-track-panel {\n z-index: 1024;\n position: absolute;\n top: 33px;\n left: 0;\n width: 100%;\n height: fit-content;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n.igv-circview-track-panel > div {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-track-panel > div > div {\n margin: 4px;\n}\n\n.igv-circview-swatch-button {\n cursor: pointer;\n padding: 5px;\n width: 8px;\n height: 8px;\n border: 1px solid #8d8b8b;\n border-radius: 16px;\n}\n\n.igv-circview-button {\n cursor: pointer;\n padding: 5px;\n color: #444;\n vertical-align: middle;\n text-align: center;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n border: 1px solid #8d8b8b;\n border-radius: 4px;\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.2);\n}\n\n.igv-circview-button:hover {\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n.igv-circview-button:active {\n color: #007bff;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n/*# sourceMappingURL=circular-view.css.map */\n';
|
|
31527
31558
|
|
|
31528
31559
|
const style = document.createElement('style');
|
|
31529
31560
|
style.setAttribute('type', 'text/css');
|
|
@@ -31562,27 +31593,45 @@ const makePairedAlignmentChords = (alignments) => {
|
|
|
31562
31593
|
|
|
31563
31594
|
const chords = [];
|
|
31564
31595
|
for (let a of alignments) {
|
|
31565
|
-
|
|
31566
|
-
if
|
|
31567
|
-
|
|
31568
|
-
|
|
31569
|
-
|
|
31570
|
-
|
|
31571
|
-
|
|
31572
|
-
|
|
31573
|
-
|
|
31574
|
-
|
|
31575
|
-
|
|
31576
|
-
|
|
31577
|
-
|
|
31596
|
+
|
|
31597
|
+
if(a.paired) {
|
|
31598
|
+
if(a.firstAlignment && a.secondAlignment) {
|
|
31599
|
+
chords.push({
|
|
31600
|
+
uniqueId: a.readName,
|
|
31601
|
+
refName: shortChrName(a.firstAlignment.chr),
|
|
31602
|
+
start: a.firstAlignment.start,
|
|
31603
|
+
end: a.firstAlignment.end,
|
|
31604
|
+
mate: {
|
|
31605
|
+
refName: shortChrName(a.secondAlignment.chr),
|
|
31606
|
+
start: a.secondAlignment.start,
|
|
31607
|
+
end: a.secondAlignment.end,
|
|
31608
|
+
}
|
|
31609
|
+
});
|
|
31610
|
+
}
|
|
31611
|
+
}
|
|
31612
|
+
else {
|
|
31613
|
+
const mate = a.mate;
|
|
31614
|
+
if (mate && mate.chr && mate.position) {
|
|
31615
|
+
chords.push({
|
|
31616
|
+
uniqueId: a.readName,
|
|
31617
|
+
refName: shortChrName(a.chr),
|
|
31618
|
+
start: a.start,
|
|
31619
|
+
end: a.end,
|
|
31620
|
+
mate: {
|
|
31621
|
+
refName: shortChrName(mate.chr),
|
|
31622
|
+
start: mate.position - 1,
|
|
31623
|
+
end: mate.position,
|
|
31624
|
+
}
|
|
31625
|
+
});
|
|
31626
|
+
}
|
|
31578
31627
|
}
|
|
31579
31628
|
}
|
|
31580
31629
|
return chords
|
|
31581
31630
|
};
|
|
31582
31631
|
|
|
31583
31632
|
const makeSupplementalAlignmentChords = (alignments) => {
|
|
31584
|
-
|
|
31585
|
-
|
|
31633
|
+
|
|
31634
|
+
const makeChords = (a) => {
|
|
31586
31635
|
const sa = a.tags()['SA'];
|
|
31587
31636
|
const supAl = createSupplementaryAlignments(sa);
|
|
31588
31637
|
let n = 0;
|
|
@@ -31601,6 +31650,18 @@ const makeSupplementalAlignmentChords = (alignments) => {
|
|
|
31601
31650
|
});
|
|
31602
31651
|
}
|
|
31603
31652
|
}
|
|
31653
|
+
};
|
|
31654
|
+
|
|
31655
|
+
const chords = [];
|
|
31656
|
+
for (let a of alignments) {
|
|
31657
|
+
if(a.paired) {
|
|
31658
|
+
makeChords(a.firstAlignment);
|
|
31659
|
+
if(a.secondAlignment) {
|
|
31660
|
+
makeChords(a.secondAlignment);
|
|
31661
|
+
}
|
|
31662
|
+
} else {
|
|
31663
|
+
makeChords(a);
|
|
31664
|
+
}
|
|
31604
31665
|
}
|
|
31605
31666
|
return chords
|
|
31606
31667
|
};
|
|
@@ -32322,11 +32383,18 @@ class BAMTrack extends TrackBase {
|
|
|
32322
32383
|
const refFrame = viewport.referenceFrame;
|
|
32323
32384
|
for (let a of viewport.cachedFeatures.allAlignments()) {
|
|
32324
32385
|
if (a.end >= refFrame.start
|
|
32325
|
-
&& a.start <= refFrame.end
|
|
32326
|
-
|
|
32327
|
-
|
|
32328
|
-
|
|
32329
|
-
|
|
32386
|
+
&& a.start <= refFrame.end) {
|
|
32387
|
+
if (a.paired) {
|
|
32388
|
+
if (a.end - a.start > maxTemplateLength) {
|
|
32389
|
+
inView.push(a);
|
|
32390
|
+
}
|
|
32391
|
+
} else {
|
|
32392
|
+
if (a.mate
|
|
32393
|
+
&& a.mate.chr
|
|
32394
|
+
&& (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxTemplateLength)) {
|
|
32395
|
+
inView.push(a);
|
|
32396
|
+
}
|
|
32397
|
+
}
|
|
32330
32398
|
}
|
|
32331
32399
|
}
|
|
32332
32400
|
const chords = makePairedAlignmentChords(inView);
|
|
@@ -33181,10 +33249,13 @@ class AlignmentTrack {
|
|
|
33181
33249
|
case "pairOrientation":
|
|
33182
33250
|
|
|
33183
33251
|
if (this.pairOrientation && alignment.pairOrientation) {
|
|
33184
|
-
|
|
33252
|
+
const oTypes = orientationTypes[this.pairOrientation];
|
|
33185
33253
|
if (oTypes) {
|
|
33186
|
-
|
|
33187
|
-
if (pairColor)
|
|
33254
|
+
const pairColor = this.pairColors[oTypes[alignment.pairOrientation]];
|
|
33255
|
+
if (pairColor) {
|
|
33256
|
+
color = pairColor;
|
|
33257
|
+
break
|
|
33258
|
+
}
|
|
33188
33259
|
}
|
|
33189
33260
|
}
|
|
33190
33261
|
if ("pairOrientation" === option) {
|
|
@@ -33902,7 +33973,7 @@ class SampleNameViewport {
|
|
|
33902
33973
|
for (let {sampleNameViewport} of this.browser.trackViews) {
|
|
33903
33974
|
sampleNameViewport.setWidth(this.browser.sampleNameViewportWidth);
|
|
33904
33975
|
}
|
|
33905
|
-
this.browser.
|
|
33976
|
+
this.browser.layoutChange();
|
|
33906
33977
|
}
|
|
33907
33978
|
};
|
|
33908
33979
|
|
|
@@ -35793,7 +35864,7 @@ function decodeBed(tokens, header) {
|
|
|
35793
35864
|
const eEnd = eStart + parseInt(exonSizes[i]);
|
|
35794
35865
|
exons.push({start: eStart, end: eEnd});
|
|
35795
35866
|
}
|
|
35796
|
-
findUTRs(exons, feature.cdStart, feature.cdEnd);
|
|
35867
|
+
findUTRs$1(exons, feature.cdStart, feature.cdEnd);
|
|
35797
35868
|
feature.exons = exons;
|
|
35798
35869
|
}
|
|
35799
35870
|
|
|
@@ -35901,7 +35972,7 @@ function decodeGenePred(tokens, header) {
|
|
|
35901
35972
|
const end = parseInt(exonEnds[i]);
|
|
35902
35973
|
exons.push({start: start, end: end});
|
|
35903
35974
|
}
|
|
35904
|
-
findUTRs(exons, cdStart, cdEnd);
|
|
35975
|
+
findUTRs$1(exons, cdStart, cdEnd);
|
|
35905
35976
|
|
|
35906
35977
|
feature.exons = exons;
|
|
35907
35978
|
|
|
@@ -35944,7 +36015,7 @@ function decodeGenePredExt(tokens, header) {
|
|
|
35944
36015
|
const end = parseInt(exonEnds[i]);
|
|
35945
36016
|
exons.push({start: start, end: end});
|
|
35946
36017
|
}
|
|
35947
|
-
findUTRs(exons, cdStart, cdEnd);
|
|
36018
|
+
findUTRs$1(exons, cdStart, cdEnd);
|
|
35948
36019
|
|
|
35949
36020
|
feature.exons = exons;
|
|
35950
36021
|
|
|
@@ -35985,14 +36056,14 @@ function decodeReflat(tokens, header) {
|
|
|
35985
36056
|
const end = parseInt(exonEnds[i]);
|
|
35986
36057
|
exons.push({start: start, end: end});
|
|
35987
36058
|
}
|
|
35988
|
-
findUTRs(exons, cdStart, cdEnd);
|
|
36059
|
+
findUTRs$1(exons, cdStart, cdEnd);
|
|
35989
36060
|
|
|
35990
36061
|
feature.exons = exons;
|
|
35991
36062
|
|
|
35992
36063
|
return feature
|
|
35993
36064
|
}
|
|
35994
36065
|
|
|
35995
|
-
function findUTRs(exons, cdStart, cdEnd) {
|
|
36066
|
+
function findUTRs$1(exons, cdStart, cdEnd) {
|
|
35996
36067
|
|
|
35997
36068
|
for (let exon of exons) {
|
|
35998
36069
|
const end = exon.end;
|
|
@@ -39508,7 +39579,7 @@ class TextFeatureSource {
|
|
|
39508
39579
|
this.sourceType = (config.sourceType === undefined ? "file" : config.sourceType);
|
|
39509
39580
|
this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
|
|
39510
39581
|
|
|
39511
|
-
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "tdf"]);
|
|
39582
|
+
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "biggenepred", "bignarrowpeak", "tdf"]);
|
|
39512
39583
|
|
|
39513
39584
|
if (config.features && Array.isArray(config.features)) {
|
|
39514
39585
|
// Explicit array of features
|
|
@@ -39928,11 +39999,9 @@ class BufferedReader {
|
|
|
39928
39999
|
}
|
|
39929
40000
|
}
|
|
39930
40001
|
|
|
39931
|
-
//table chromatinInteract
|
|
39932
|
-
|
|
39933
40002
|
function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
39934
40003
|
|
|
39935
|
-
if (autoSql && 'chromatinInteract' === autoSql.table ||
|
|
40004
|
+
if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table) || 'interact' === autoSql.table)) {
|
|
39936
40005
|
return decodeInteract
|
|
39937
40006
|
} else {
|
|
39938
40007
|
const standardFieldCount = definedFieldCount - 3;
|
|
@@ -39969,6 +40038,7 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
|
39969
40038
|
const eEnd = eStart + parseInt(exonSizes[i]);
|
|
39970
40039
|
exons.push({start: eStart, end: eEnd});
|
|
39971
40040
|
}
|
|
40041
|
+
findUTRs(exons, feature.cdStart, feature.cdEnd);
|
|
39972
40042
|
feature.exons = exons;
|
|
39973
40043
|
}
|
|
39974
40044
|
|
|
@@ -39986,6 +40056,28 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
|
39986
40056
|
}
|
|
39987
40057
|
}
|
|
39988
40058
|
|
|
40059
|
+
//table chromatinInteract
|
|
40060
|
+
// "Chromatin interaction between two regions"
|
|
40061
|
+
// (
|
|
40062
|
+
// string chrom; "Chromosome (or contig, scaffold, etc.). For interchromosomal, use 2 records"
|
|
40063
|
+
// uint chromStart; "Start position of lower region. For interchromosomal, set to chromStart of this region"
|
|
40064
|
+
// uint chromEnd; "End position of upper region. For interchromosomal, set to chromEnd of this region"
|
|
40065
|
+
// string name; "Name of item, for display"
|
|
40066
|
+
// uint score; "Score from 0-1000"
|
|
40067
|
+
// double value; "Strength of interaction or other data value. Typically basis for score"
|
|
40068
|
+
// string exp; "Experiment name (metadata for filtering). Use . if not applicable"
|
|
40069
|
+
// string color; "Item color. Specified as r,g,b or hexadecimal #RRGGBB or html color name, as in //www.w3.org/TR/css3-color/#html4."
|
|
40070
|
+
// string region1Chrom; "Chromosome of lower region. For non-directional interchromosomal, chrom of this region."
|
|
40071
|
+
// uint region1Start; "Start position of lower/this region"
|
|
40072
|
+
// uint region1End; "End position in chromosome of lower/this region"
|
|
40073
|
+
// string region1Name; "Identifier of lower/this region"
|
|
40074
|
+
// string region1Strand; "Orientation of lower/this region: + or -. Use . if not applicable"
|
|
40075
|
+
// string region2Chrom; "Chromosome of upper region. For non-directional interchromosomal, chrom of other region"
|
|
40076
|
+
// uint region2Start; "Start position in chromosome of upper/this region"
|
|
40077
|
+
// uint region2End; "End position in chromosome of upper/this region"
|
|
40078
|
+
// string region2Name; "Identifier of upper/this region"
|
|
40079
|
+
// string region2Strand; "Orientation of upper/this region: + or -. Use . if not applicable"
|
|
40080
|
+
// )
|
|
39989
40081
|
function decodeInteract(feature, tokens) {
|
|
39990
40082
|
|
|
39991
40083
|
feature.chr1 = tokens[5];
|
|
@@ -40005,6 +40097,24 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
|
40005
40097
|
}
|
|
40006
40098
|
}
|
|
40007
40099
|
|
|
40100
|
+
function findUTRs(exons, cdStart, cdEnd) {
|
|
40101
|
+
|
|
40102
|
+
for (let exon of exons) {
|
|
40103
|
+
const end = exon.end;
|
|
40104
|
+
const start = exon.start;
|
|
40105
|
+
if (end < cdStart || start > cdEnd) {
|
|
40106
|
+
exon.utr = true;
|
|
40107
|
+
} else {
|
|
40108
|
+
if (cdStart >= start && cdStart <= end) {
|
|
40109
|
+
exon.cdStart = cdStart;
|
|
40110
|
+
}
|
|
40111
|
+
if (cdEnd >= start && cdEnd <= end) {
|
|
40112
|
+
exon.cdEnd = cdEnd;
|
|
40113
|
+
}
|
|
40114
|
+
}
|
|
40115
|
+
}
|
|
40116
|
+
}
|
|
40117
|
+
|
|
40008
40118
|
function scoreShade(score, color) {
|
|
40009
40119
|
const alpha = Math.min(1, 0.11 + 0.89 * (score / 779));
|
|
40010
40120
|
return alpha.toString()
|
|
@@ -41544,11 +41654,12 @@ function zoomLevelForScale(chr, bpPerPixel, genome) {
|
|
|
41544
41654
|
* THE SOFTWARE.
|
|
41545
41655
|
*/
|
|
41546
41656
|
|
|
41657
|
+
const bbFormats = new Set(['bigwig', 'bw', 'bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
|
|
41547
41658
|
|
|
41548
41659
|
function FeatureSource(config, genome) {
|
|
41549
41660
|
|
|
41550
41661
|
const format = config.format ? config.format.toLowerCase() : undefined;
|
|
41551
|
-
if (
|
|
41662
|
+
if (bbFormats.has(format)) {
|
|
41552
41663
|
return new BWSource(config, genome)
|
|
41553
41664
|
} else if ("tdf" === format) {
|
|
41554
41665
|
return new TDFSource(config, genome)
|
|
@@ -41796,10 +41907,9 @@ function renderFeatureLabel(ctx, feature, featureX, featureX1, featureY, referen
|
|
|
41796
41907
|
const textBox = ctx.measureText(name);
|
|
41797
41908
|
const xleft = centerX - textBox.width / 2;
|
|
41798
41909
|
const xright = centerX + textBox.width / 2;
|
|
41799
|
-
if (options.labelAllFeatures || xleft > options.
|
|
41800
|
-
options.
|
|
41910
|
+
if (options.labelAllFeatures || xleft > options.rowLastLabelX[feature.row] || gtexSelection) {
|
|
41911
|
+
options.rowLastLabelX[feature.row] = xright;
|
|
41801
41912
|
IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
|
|
41802
|
-
|
|
41803
41913
|
}
|
|
41804
41914
|
} finally {
|
|
41805
41915
|
ctx.restore();
|
|
@@ -42156,24 +42266,27 @@ class FeatureTrack extends TrackBase {
|
|
|
42156
42266
|
|
|
42157
42267
|
const rowFeatureCount = [];
|
|
42158
42268
|
options.rowLastX = [];
|
|
42269
|
+
options.rowLastLabelX = [];
|
|
42159
42270
|
for (let feature of featureList) {
|
|
42160
|
-
|
|
42161
|
-
|
|
42162
|
-
rowFeatureCount[row]
|
|
42163
|
-
|
|
42164
|
-
|
|
42271
|
+
if(feature.start > bpStart && feature.end < bpEnd) {
|
|
42272
|
+
const row = this.displayMode === "COLLAPSED" ? 0 : feature.row || 0;
|
|
42273
|
+
if (rowFeatureCount[row] === undefined) {
|
|
42274
|
+
rowFeatureCount[row] = 1;
|
|
42275
|
+
} else {
|
|
42276
|
+
rowFeatureCount[row]++;
|
|
42277
|
+
}
|
|
42278
|
+
options.rowLastX[row] = -Number.MAX_SAFE_INTEGER;
|
|
42279
|
+
options.rowLastLabelX[row] = -Number.MAX_SAFE_INTEGER;
|
|
42165
42280
|
}
|
|
42166
|
-
options.rowLastX[row] = -Number.MAX_SAFE_INTEGER;
|
|
42167
42281
|
}
|
|
42282
|
+
const pixelsPerFeature = pixelWidth / Math.max(...rowFeatureCount);
|
|
42168
42283
|
|
|
42169
42284
|
let lastPxEnd = [];
|
|
42170
42285
|
for (let feature of featureList) {
|
|
42171
42286
|
if (feature.end < bpStart) continue
|
|
42172
42287
|
if (feature.start > bpEnd) break
|
|
42173
|
-
|
|
42174
42288
|
const row = this.displayMode === 'COLLAPSED' ? 0 : feature.row;
|
|
42175
|
-
|
|
42176
|
-
options.drawLabel = options.labelAllFeatures || featureDensity > 10;
|
|
42289
|
+
options.drawLabel = options.labelAllFeatures || pixelsPerFeature > 10;
|
|
42177
42290
|
const pxEnd = Math.ceil((feature.end - bpStart) / bpPerPixel);
|
|
42178
42291
|
const last = lastPxEnd[row];
|
|
42179
42292
|
if (!last || pxEnd > last) {
|
|
@@ -42187,7 +42300,6 @@ class FeatureTrack extends TrackBase {
|
|
|
42187
42300
|
ctx.globalAlpha = 1.0;
|
|
42188
42301
|
}
|
|
42189
42302
|
lastPxEnd[row] = pxEnd;
|
|
42190
|
-
|
|
42191
42303
|
}
|
|
42192
42304
|
}
|
|
42193
42305
|
|
|
@@ -48594,7 +48706,7 @@ class SampleNameControl {
|
|
|
48594
48706
|
}
|
|
48595
48707
|
}
|
|
48596
48708
|
|
|
48597
|
-
browser.
|
|
48709
|
+
browser.layoutChange();
|
|
48598
48710
|
|
|
48599
48711
|
|
|
48600
48712
|
});
|
|
@@ -50264,7 +50376,16 @@ class Browser {
|
|
|
50264
50376
|
|
|
50265
50377
|
}
|
|
50266
50378
|
|
|
50379
|
+
/**
|
|
50380
|
+
* API function to signal that this browser visibility has changed, e.g. from hiding/showing in a tab interface.
|
|
50381
|
+
*
|
|
50382
|
+
* @returns {Promise<void>}
|
|
50383
|
+
*/
|
|
50267
50384
|
async visibilityChange() {
|
|
50385
|
+
this.layoutChange();
|
|
50386
|
+
}
|
|
50387
|
+
|
|
50388
|
+
async layoutChange() {
|
|
50268
50389
|
|
|
50269
50390
|
const status = this.referenceFrameList.find(referenceFrame => referenceFrame.bpPerPixel < 0);
|
|
50270
50391
|
|
|
@@ -51005,6 +51126,7 @@ class Browser {
|
|
|
51005
51126
|
}
|
|
51006
51127
|
|
|
51007
51128
|
createCircularView(container, show) {
|
|
51129
|
+
show = show === true; // convert undefined to boolean
|
|
51008
51130
|
this.circularView = createCircularView(container, this);
|
|
51009
51131
|
this.circularViewControl = new CircularViewControl(this.$toggle_button_container.get(0), this);
|
|
51010
51132
|
this.circularView.setAssembly({
|
|
@@ -51013,7 +51135,7 @@ class Browser {
|
|
|
51013
51135
|
chromosomes: makeCircViewChromosomes(this.genome)
|
|
51014
51136
|
});
|
|
51015
51137
|
this.circularViewVisible = show;
|
|
51016
|
-
|
|
51138
|
+
return this.circularView
|
|
51017
51139
|
}
|
|
51018
51140
|
|
|
51019
51141
|
get circularViewVisible() {
|