igv 2.13.7 → 2.13.8
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 +378 -179
- package/dist/igv.esm.min.js +8 -8
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +395 -172
- package/dist/igv.min.js +5 -5
- package/dist/igv.min.js.map +1 -1
- package/package.json +1 -1
package/dist/igv.esm.js
CHANGED
|
@@ -15473,7 +15473,7 @@ function download(filename, data) {
|
|
|
15473
15473
|
|
|
15474
15474
|
const { Deflate, deflate, deflateRaw, gzip } = deflate_1$1;
|
|
15475
15475
|
|
|
15476
|
-
const { Inflate, inflate: inflate$3, inflateRaw, ungzip: ungzip$2 } = inflate_1$1;
|
|
15476
|
+
const { Inflate, inflate: inflate$3, inflateRaw: inflateRaw$2, ungzip: ungzip$2 } = inflate_1$1;
|
|
15477
15477
|
|
|
15478
15478
|
|
|
15479
15479
|
|
|
@@ -15483,7 +15483,7 @@ function download(filename, data) {
|
|
|
15483
15483
|
var gzip_1 = gzip;
|
|
15484
15484
|
var Inflate_1 = Inflate;
|
|
15485
15485
|
var inflate_1 = inflate$3;
|
|
15486
|
-
var inflateRaw_1 = inflateRaw;
|
|
15486
|
+
var inflateRaw_1 = inflateRaw$2;
|
|
15487
15487
|
var ungzip_1 = ungzip$2;
|
|
15488
15488
|
var constants_1 = constants$2;
|
|
15489
15489
|
|
|
@@ -15517,7 +15517,7 @@ function download(filename, data) {
|
|
|
15517
15517
|
|
|
15518
15518
|
pako.deflateRaw;
|
|
15519
15519
|
pako.deflate;
|
|
15520
|
-
pako.inflateRaw;
|
|
15520
|
+
const inflateRaw = pako.inflateRaw;
|
|
15521
15521
|
const inflate = pako.inflate;
|
|
15522
15522
|
pako.gzip;
|
|
15523
15523
|
|
|
@@ -15595,7 +15595,7 @@ function unbgzf(data, lim) {
|
|
|
15595
15595
|
}
|
|
15596
15596
|
}
|
|
15597
15597
|
|
|
15598
|
-
function bgzBlockSize(data) {
|
|
15598
|
+
function bgzBlockSize$1(data) {
|
|
15599
15599
|
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
15600
15600
|
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
15601
15601
|
return bsize;
|
|
@@ -20792,7 +20792,7 @@ function buildOptions(config, options) {
|
|
|
20792
20792
|
const doAutoscale = function (features) {
|
|
20793
20793
|
var min, max;
|
|
20794
20794
|
|
|
20795
|
-
if (features.length > 0) {
|
|
20795
|
+
if (features && features.length > 0) {
|
|
20796
20796
|
min = Number.MAX_VALUE;
|
|
20797
20797
|
max = -Number.MAX_VALUE;
|
|
20798
20798
|
|
|
@@ -24215,7 +24215,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
24215
24215
|
}
|
|
24216
24216
|
};
|
|
24217
24217
|
|
|
24218
|
-
const _version = "2.13.
|
|
24218
|
+
const _version = "2.13.8";
|
|
24219
24219
|
function version() {
|
|
24220
24220
|
return _version
|
|
24221
24221
|
}
|
|
@@ -29233,12 +29233,88 @@ class VPointer {
|
|
|
29233
29233
|
(this.block === vp.block && this.offset > vp.offset)
|
|
29234
29234
|
}
|
|
29235
29235
|
|
|
29236
|
+
isEqualTo(vp) {
|
|
29237
|
+
return this.block === vp.block && this.offset === vp.offset
|
|
29238
|
+
}
|
|
29239
|
+
|
|
29236
29240
|
print() {
|
|
29237
29241
|
return "" + this.block + ":" + this.offset
|
|
29238
29242
|
}
|
|
29239
29243
|
}
|
|
29240
29244
|
|
|
29241
|
-
|
|
29245
|
+
function optimizeChunks(chunks, lowest) {
|
|
29246
|
+
|
|
29247
|
+
if (chunks.length === 0) return chunks
|
|
29248
|
+
|
|
29249
|
+
chunks.sort(function (c0, c1) {
|
|
29250
|
+
|
|
29251
|
+
const dif = c0.minv.block - c1.minv.block;
|
|
29252
|
+
if (dif !== 0) {
|
|
29253
|
+
return dif
|
|
29254
|
+
} else {
|
|
29255
|
+
return c0.minv.offset - c1.minv.offset
|
|
29256
|
+
}
|
|
29257
|
+
});
|
|
29258
|
+
|
|
29259
|
+
if(chunks.length <= 1) {
|
|
29260
|
+
return chunks
|
|
29261
|
+
}
|
|
29262
|
+
|
|
29263
|
+
// console.log("Before trimming " + chunks.length)
|
|
29264
|
+
// for (let c of chunks) {
|
|
29265
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29266
|
+
// }
|
|
29267
|
+
|
|
29268
|
+
if (lowest) {
|
|
29269
|
+
chunks = chunks.filter(c => c.maxv.isGreaterThan(lowest));
|
|
29270
|
+
}
|
|
29271
|
+
|
|
29272
|
+
// console.log("Before merging " + chunks.length)
|
|
29273
|
+
// for (let c of chunks) {
|
|
29274
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29275
|
+
// }
|
|
29276
|
+
|
|
29277
|
+
const mergedChunks = [];
|
|
29278
|
+
let lastChunk;
|
|
29279
|
+
for (let chunk of chunks) {
|
|
29280
|
+
|
|
29281
|
+
if (!lastChunk) {
|
|
29282
|
+
mergedChunks.push(chunk);
|
|
29283
|
+
lastChunk = chunk;
|
|
29284
|
+
} else {
|
|
29285
|
+
if (canMerge(lastChunk, chunk)) {
|
|
29286
|
+
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29287
|
+
lastChunk.maxv = chunk.maxv;
|
|
29288
|
+
}
|
|
29289
|
+
} else {
|
|
29290
|
+
mergedChunks.push(chunk);
|
|
29291
|
+
lastChunk = chunk;
|
|
29292
|
+
}
|
|
29293
|
+
}
|
|
29294
|
+
}
|
|
29295
|
+
|
|
29296
|
+
// console.log("After merging " + mergedChunks.length)
|
|
29297
|
+
// for (let c of mergedChunks) {
|
|
29298
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29299
|
+
// }
|
|
29300
|
+
|
|
29301
|
+
return mergedChunks
|
|
29302
|
+
}
|
|
29303
|
+
|
|
29304
|
+
|
|
29305
|
+
/**
|
|
29306
|
+
* Merge 2 blocks if the file position gap between them is < 16 kb, and the total size is < ~5 mb
|
|
29307
|
+
* @param chunk1
|
|
29308
|
+
* @param chunk2
|
|
29309
|
+
* @returns {boolean|boolean}
|
|
29310
|
+
*/
|
|
29311
|
+
function canMerge(chunk1, chunk2) {
|
|
29312
|
+
const gap = chunk2.minv.block - chunk1.maxv.block;
|
|
29313
|
+
const sizeEstimate = chunk1.maxv.block - chunk1.minv.block;
|
|
29314
|
+
return gap < 65000 && sizeEstimate < 5000000
|
|
29315
|
+
}
|
|
29316
|
+
|
|
29317
|
+
// Represents a CSI Bam or Tabix index
|
|
29242
29318
|
|
|
29243
29319
|
const CSI1_MAGIC$1 = 21582659; // CSI\1
|
|
29244
29320
|
const CSI2_MAGIC$1 = 38359875; // CSI\2
|
|
@@ -29365,7 +29441,7 @@ class CSIIndex {
|
|
|
29365
29441
|
* @param max genomic end position
|
|
29366
29442
|
* @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
|
|
29367
29443
|
*/
|
|
29368
|
-
|
|
29444
|
+
chunksForRange(refId, min, max) {
|
|
29369
29445
|
|
|
29370
29446
|
const ba = this.indices[refId];
|
|
29371
29447
|
if (!ba) {
|
|
@@ -29391,7 +29467,7 @@ class CSIIndex {
|
|
|
29391
29467
|
|
|
29392
29468
|
const lowestOffset = ba.loffset[overlappingBins[0]];
|
|
29393
29469
|
|
|
29394
|
-
return optimizeChunks
|
|
29470
|
+
return optimizeChunks(chunks, lowestOffset)
|
|
29395
29471
|
}
|
|
29396
29472
|
|
|
29397
29473
|
}
|
|
@@ -29428,58 +29504,11 @@ class CSIIndex {
|
|
|
29428
29504
|
|
|
29429
29505
|
}
|
|
29430
29506
|
|
|
29431
|
-
|
|
29432
|
-
|
|
29433
|
-
const mergedChunks = [];
|
|
29434
|
-
let lastChunk = null;
|
|
29435
|
-
|
|
29436
|
-
if (chunks.length === 0) return chunks
|
|
29437
|
-
|
|
29438
|
-
chunks.sort(function (c0, c1) {
|
|
29439
|
-
const dif = c0.minv.block - c1.minv.block;
|
|
29440
|
-
if (dif !== 0) {
|
|
29441
|
-
return dif
|
|
29442
|
-
} else {
|
|
29443
|
-
return c0.minv.offset - c1.minv.offset
|
|
29444
|
-
}
|
|
29445
|
-
});
|
|
29446
|
-
|
|
29447
|
-
chunks.forEach(function (chunk) {
|
|
29448
|
-
|
|
29449
|
-
if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
|
|
29450
|
-
if (lastChunk === null) {
|
|
29451
|
-
mergedChunks.push(chunk);
|
|
29452
|
-
lastChunk = chunk;
|
|
29453
|
-
} else {
|
|
29454
|
-
if (canMerge$1(lastChunk, chunk)) {
|
|
29455
|
-
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29456
|
-
lastChunk.maxv = chunk.maxv;
|
|
29457
|
-
}
|
|
29458
|
-
} else {
|
|
29459
|
-
mergedChunks.push(chunk);
|
|
29460
|
-
lastChunk = chunk;
|
|
29461
|
-
}
|
|
29462
|
-
}
|
|
29463
|
-
}
|
|
29464
|
-
});
|
|
29465
|
-
|
|
29466
|
-
return mergedChunks
|
|
29467
|
-
}
|
|
29468
|
-
|
|
29469
|
-
function canMerge$1(chunk1, chunk2) {
|
|
29470
|
-
return (chunk2.minv.block - chunk1.maxv.block) < 65000 &&
|
|
29471
|
-
(chunk2.maxv.block - chunk1.minv.block) < 5000000
|
|
29472
|
-
// lastChunk.minv.block === lastChunk.maxv.block &&
|
|
29473
|
-
// lastChunk.maxv.block === chunk.minv.block &&
|
|
29474
|
-
// chunk.minv.block === chunk.maxv.block
|
|
29475
|
-
|
|
29476
|
-
}
|
|
29477
|
-
|
|
29478
|
-
// Represents a BAM index.
|
|
29507
|
+
// Represents a BAM or Tabix index.
|
|
29479
29508
|
|
|
29480
29509
|
const BAI_MAGIC$1 = 21578050;
|
|
29481
29510
|
const TABIX_MAGIC$1 = 21578324;
|
|
29482
|
-
|
|
29511
|
+
|
|
29483
29512
|
|
|
29484
29513
|
async function parseBamIndex(arrayBuffer, genome) {
|
|
29485
29514
|
const index = new BamIndex();
|
|
@@ -29601,14 +29630,14 @@ class BamIndex {
|
|
|
29601
29630
|
}
|
|
29602
29631
|
|
|
29603
29632
|
/**
|
|
29604
|
-
* Fetch
|
|
29633
|
+
* Fetch chunks for a particular genomic range. This method is public so it can be unit-tested.
|
|
29605
29634
|
*
|
|
29606
29635
|
* @param refId the sequence dictionary index of the chromosome
|
|
29607
29636
|
* @param min genomic start position
|
|
29608
29637
|
* @param max genomic end position
|
|
29609
|
-
* @param return an array of {minv: {
|
|
29638
|
+
* @param return an array of objects representing chunks (file spans) {minv: {block, offset}, {maxv: {block, offset}}
|
|
29610
29639
|
*/
|
|
29611
|
-
|
|
29640
|
+
chunksForRange(refId, min, max) {
|
|
29612
29641
|
|
|
29613
29642
|
const bam = this;
|
|
29614
29643
|
const ba = bam.indices[refId];
|
|
@@ -29617,8 +29646,13 @@ class BamIndex {
|
|
|
29617
29646
|
return []
|
|
29618
29647
|
} else {
|
|
29619
29648
|
const overlappingBins = reg2bins(min, max); // List of bin #s that overlap min, max
|
|
29620
|
-
const chunks = [];
|
|
29621
29649
|
|
|
29650
|
+
//console.log("bin ranges")
|
|
29651
|
+
//for(let b of overlappingBins) {
|
|
29652
|
+
// console.log(`${b[0]} - ${b[1]}`)
|
|
29653
|
+
//}
|
|
29654
|
+
|
|
29655
|
+
const chunks = [];
|
|
29622
29656
|
// Find chunks in overlapping bins. Leaf bins (< 4681) are not pruned
|
|
29623
29657
|
for (let binRange of overlappingBins) {
|
|
29624
29658
|
for (let bin = binRange[0]; bin <= binRange[1]; bin++) {
|
|
@@ -29627,7 +29661,7 @@ class BamIndex {
|
|
|
29627
29661
|
for (let c of binChunks) {
|
|
29628
29662
|
const cs = c[0];
|
|
29629
29663
|
const ce = c[1];
|
|
29630
|
-
chunks.push({minv: cs, maxv: ce
|
|
29664
|
+
chunks.push({minv: cs, maxv: ce});
|
|
29631
29665
|
}
|
|
29632
29666
|
}
|
|
29633
29667
|
}
|
|
@@ -29635,16 +29669,15 @@ class BamIndex {
|
|
|
29635
29669
|
|
|
29636
29670
|
// Use the linear index to find minimum file position of chunks that could contain alignments in the region
|
|
29637
29671
|
const nintv = ba.linearIndex.length;
|
|
29638
|
-
|
|
29639
|
-
|
|
29672
|
+
|
|
29673
|
+
let lowest;
|
|
29674
|
+
const minLin = Math.min(min >> 14, nintv - 1); // i.e. min / 16384
|
|
29640
29675
|
const maxLin = Math.min(max >> 14, nintv - 1);
|
|
29641
|
-
for (let i = minLin; i
|
|
29676
|
+
for (let i = minLin; i <= maxLin; i++) {
|
|
29642
29677
|
const vp = ba.linearIndex[i];
|
|
29643
29678
|
if (vp) {
|
|
29644
|
-
|
|
29645
|
-
|
|
29646
|
-
lowest = vp;
|
|
29647
|
-
}
|
|
29679
|
+
lowest = vp; // lowest file offset that contains alignments overlapping (min, max)
|
|
29680
|
+
break
|
|
29648
29681
|
}
|
|
29649
29682
|
}
|
|
29650
29683
|
|
|
@@ -29653,56 +29686,7 @@ class BamIndex {
|
|
|
29653
29686
|
}
|
|
29654
29687
|
}
|
|
29655
29688
|
|
|
29656
|
-
function optimizeChunks(chunks, lowest) {
|
|
29657
29689
|
|
|
29658
|
-
const mergedChunks = [];
|
|
29659
|
-
let lastChunk = null;
|
|
29660
|
-
|
|
29661
|
-
if (chunks.length === 0) return chunks
|
|
29662
|
-
|
|
29663
|
-
chunks.sort(function (c0, c1) {
|
|
29664
|
-
const dif = c0.minv.block - c1.minv.block;
|
|
29665
|
-
if (dif !== 0) {
|
|
29666
|
-
return dif
|
|
29667
|
-
} else {
|
|
29668
|
-
return c0.minv.offset - c1.minv.offset
|
|
29669
|
-
}
|
|
29670
|
-
});
|
|
29671
|
-
|
|
29672
|
-
chunks.forEach(function (chunk) {
|
|
29673
|
-
|
|
29674
|
-
if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
|
|
29675
|
-
if (lastChunk === null) {
|
|
29676
|
-
mergedChunks.push(chunk);
|
|
29677
|
-
lastChunk = chunk;
|
|
29678
|
-
} else {
|
|
29679
|
-
if (canMerge(lastChunk, chunk)) {
|
|
29680
|
-
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29681
|
-
lastChunk.maxv = chunk.maxv;
|
|
29682
|
-
}
|
|
29683
|
-
} else {
|
|
29684
|
-
mergedChunks.push(chunk);
|
|
29685
|
-
lastChunk = chunk;
|
|
29686
|
-
}
|
|
29687
|
-
}
|
|
29688
|
-
}
|
|
29689
|
-
});
|
|
29690
|
-
|
|
29691
|
-
return mergedChunks
|
|
29692
|
-
}
|
|
29693
|
-
|
|
29694
|
-
|
|
29695
|
-
/**
|
|
29696
|
-
* Merge 2 blocks if the gap between them is < 1kb and the total resulting size < 100mb
|
|
29697
|
-
* @param chunk1
|
|
29698
|
-
* @param chunk2
|
|
29699
|
-
* @returns {boolean|boolean}
|
|
29700
|
-
*/
|
|
29701
|
-
function canMerge(chunk1, chunk2) {
|
|
29702
|
-
const gap = chunk2.minv.block - chunk1.maxv.block;
|
|
29703
|
-
const total = chunk2.maxv.block - chunk1.minv.block;
|
|
29704
|
-
return gap < 30000 && total < 10 * MB
|
|
29705
|
-
}
|
|
29706
29690
|
|
|
29707
29691
|
/**
|
|
29708
29692
|
* Calculate the list of bins that overlap with region [beg, end]
|
|
@@ -29840,7 +29824,7 @@ class TribbleIndex {
|
|
|
29840
29824
|
* @param min genomic start position
|
|
29841
29825
|
* @param max genomic end position
|
|
29842
29826
|
*/
|
|
29843
|
-
|
|
29827
|
+
chunksForRange(queryChr, min, max) { //function (refId, min, max) {
|
|
29844
29828
|
const chrIdx = this.chrIndex[queryChr];
|
|
29845
29829
|
|
|
29846
29830
|
if (chrIdx) {
|
|
@@ -30007,7 +29991,12 @@ class ByteArrayDataWrapper {
|
|
|
30007
29991
|
|
|
30008
29992
|
}
|
|
30009
29993
|
|
|
30010
|
-
|
|
29994
|
+
/**
|
|
29995
|
+
* Class to iterate line-by-line over a BGZipped text file. This class is useful for iterating from the start of
|
|
29996
|
+
* the file. Not useful for indexed queries.
|
|
29997
|
+
*/
|
|
29998
|
+
|
|
29999
|
+
class BGZLineReader {
|
|
30011
30000
|
|
|
30012
30001
|
constructor(config) {
|
|
30013
30002
|
this.config = config;
|
|
@@ -30053,7 +30042,7 @@ class BGZipLineReader {
|
|
|
30053
30042
|
}
|
|
30054
30043
|
});
|
|
30055
30044
|
const abuffer = await igvxhr.loadArrayBuffer(this.config.url, bsizeOptions);
|
|
30056
|
-
const bufferSize = bgzBlockSize(abuffer);
|
|
30045
|
+
const bufferSize = bgzBlockSize$1(abuffer);
|
|
30057
30046
|
//console.log(`next block ${this.filePtr} ${bufferSize}`);
|
|
30058
30047
|
|
|
30059
30048
|
if (bufferSize === 0) {
|
|
@@ -30074,6 +30063,250 @@ class BGZipLineReader {
|
|
|
30074
30063
|
|
|
30075
30064
|
}
|
|
30076
30065
|
|
|
30066
|
+
function concatenateArrayBuffers(arrayBuffers) {
|
|
30067
|
+
|
|
30068
|
+
if (arrayBuffers.length === 1) {
|
|
30069
|
+
return arrayBuffers[0]
|
|
30070
|
+
}
|
|
30071
|
+
|
|
30072
|
+
let len = 0;
|
|
30073
|
+
for (const b of arrayBuffers) {
|
|
30074
|
+
len += b.byteLength;
|
|
30075
|
+
}
|
|
30076
|
+
const c = new Uint8Array(len);
|
|
30077
|
+
let offset = 0;
|
|
30078
|
+
for (const b of arrayBuffers) {
|
|
30079
|
+
c.set(new Uint8Array(b), offset);
|
|
30080
|
+
offset += b.byteLength;
|
|
30081
|
+
}
|
|
30082
|
+
return c.buffer
|
|
30083
|
+
}
|
|
30084
|
+
|
|
30085
|
+
/**
|
|
30086
|
+
* Return the block size for the data buffer.
|
|
30087
|
+
* @param data
|
|
30088
|
+
* @returns {number}
|
|
30089
|
+
*/
|
|
30090
|
+
const bgzBlockSize = (data) => {
|
|
30091
|
+
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
30092
|
+
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
30093
|
+
return bsize
|
|
30094
|
+
};
|
|
30095
|
+
|
|
30096
|
+
class BGZBlockLoader {
|
|
30097
|
+
|
|
30098
|
+
constructor(config) {
|
|
30099
|
+
this.config = config;
|
|
30100
|
+
this.cacheBlocks = false != config.cacheBlocks; // Default to true
|
|
30101
|
+
this.cache = undefined;
|
|
30102
|
+
}
|
|
30103
|
+
|
|
30104
|
+
/**
|
|
30105
|
+
* Return inflated data from startBlock through endBlock as an UInt8Array
|
|
30106
|
+
*
|
|
30107
|
+
* @param startBlock
|
|
30108
|
+
* @param endBlock
|
|
30109
|
+
* @returns {Promise<Uint8Array>}
|
|
30110
|
+
*/
|
|
30111
|
+
async getData(startBlock, endBlock) {
|
|
30112
|
+
|
|
30113
|
+
const blocks = await this.getInflatedBlocks(startBlock, endBlock);
|
|
30114
|
+
if (blocks.length === 1) {
|
|
30115
|
+
return blocks[0]
|
|
30116
|
+
}
|
|
30117
|
+
|
|
30118
|
+
let len = 0;
|
|
30119
|
+
for (const b of blocks) {
|
|
30120
|
+
len += b.byteLength;
|
|
30121
|
+
}
|
|
30122
|
+
const c = new Uint8Array(len);
|
|
30123
|
+
let offset = 0;
|
|
30124
|
+
for (const b of blocks) {
|
|
30125
|
+
c.set(b, offset);
|
|
30126
|
+
offset += b.byteLength;
|
|
30127
|
+
}
|
|
30128
|
+
return c
|
|
30129
|
+
}
|
|
30130
|
+
|
|
30131
|
+
/**
|
|
30132
|
+
* Return the inflated data for the specified blocks as an array of Uint8Arrays. This method is public so
|
|
30133
|
+
* it can be unit tested. *
|
|
30134
|
+
* @param startBlock
|
|
30135
|
+
* @param endBlock
|
|
30136
|
+
* @returns {Promise<*[Uint8Array]>}
|
|
30137
|
+
*/
|
|
30138
|
+
async getInflatedBlocks(startBlock, endBlock) {
|
|
30139
|
+
|
|
30140
|
+
if (!this.cacheBlocks) {
|
|
30141
|
+
const buffer = await this.loadBLockData(startBlock, endBlock);
|
|
30142
|
+
return inflateBlocks(buffer)
|
|
30143
|
+
} else {
|
|
30144
|
+
|
|
30145
|
+
const c = this.cache;
|
|
30146
|
+
if (c && (c.startBlock <= startBlock && c.endBlock >= endBlock)) {
|
|
30147
|
+
//console.log("Complete overlap")
|
|
30148
|
+
const startOffset = startBlock - c.startBlock;
|
|
30149
|
+
const endOffset = endBlock - c.startBlock;
|
|
30150
|
+
return inflateBlocks(c.buffer, startOffset, endOffset)
|
|
30151
|
+
// Don't update cache, still valid
|
|
30152
|
+
} else {
|
|
30153
|
+
|
|
30154
|
+
let buffer;
|
|
30155
|
+
if (!c || (c.startBlock > endBlock || c.endBlock < startBlock)) {
|
|
30156
|
+
// no overlap with cache
|
|
30157
|
+
buffer = await this.loadBLockData(startBlock, endBlock);
|
|
30158
|
+
} else {
|
|
30159
|
+
|
|
30160
|
+
//console.log("Some overlap")
|
|
30161
|
+
const arrayBuffers = [];
|
|
30162
|
+
|
|
30163
|
+
// Load blocks preceding cache start, if any
|
|
30164
|
+
if (startBlock < c.startBlock) {
|
|
30165
|
+
// load first blocks
|
|
30166
|
+
const startBuffer = await this.loadBLockData(startBlock, c.startBlock, {skipEnd: true});
|
|
30167
|
+
arrayBuffers.push(startBuffer);
|
|
30168
|
+
}
|
|
30169
|
+
|
|
30170
|
+
// Slice cached buffer as needed
|
|
30171
|
+
let cachedBuffer;
|
|
30172
|
+
if (startBlock <= c.startBlock && endBlock >= c.endBlock) {
|
|
30173
|
+
cachedBuffer = c.buffer;
|
|
30174
|
+
} else {
|
|
30175
|
+
const start = Math.max(0, startBlock - c.startBlock);
|
|
30176
|
+
let end;
|
|
30177
|
+
if (endBlock >= c.endBlock) {
|
|
30178
|
+
end = c.buffer.byteLength;
|
|
30179
|
+
} else {
|
|
30180
|
+
// We need to find the byte position of the end of "endBlock"
|
|
30181
|
+
const boundaries = findBlockBoundaries(c.buffer);
|
|
30182
|
+
for (let i = 0; i < boundaries.length - 1; i++) {
|
|
30183
|
+
if (c.startBlock + boundaries[i] === endBlock) {
|
|
30184
|
+
end = boundaries[i + 1];
|
|
30185
|
+
break
|
|
30186
|
+
}
|
|
30187
|
+
}
|
|
30188
|
+
// Do something if end not found
|
|
30189
|
+
}
|
|
30190
|
+
cachedBuffer = c.buffer.slice(start, end);
|
|
30191
|
+
}
|
|
30192
|
+
arrayBuffers.push(cachedBuffer);
|
|
30193
|
+
|
|
30194
|
+
// Load end blocks, if any
|
|
30195
|
+
if (endBlock > c.endBlock) {
|
|
30196
|
+
const endBuffer = await this.loadBLockData(c.endBlock, endBlock, {skipStart: true});
|
|
30197
|
+
arrayBuffers.push(endBuffer);
|
|
30198
|
+
}
|
|
30199
|
+
|
|
30200
|
+
buffer = concatenateArrayBuffers(arrayBuffers);
|
|
30201
|
+
}
|
|
30202
|
+
|
|
30203
|
+
this.cache = {startBlock, endBlock, buffer};
|
|
30204
|
+
return inflateBlocks(buffer)
|
|
30205
|
+
}
|
|
30206
|
+
}
|
|
30207
|
+
}
|
|
30208
|
+
|
|
30209
|
+
async loadBLockData(startBlock, endBlock, options) {
|
|
30210
|
+
|
|
30211
|
+
const config = this.config;
|
|
30212
|
+
const skipStart = options && options.skipStart;
|
|
30213
|
+
const skipEnd = options && options.skipEnd;
|
|
30214
|
+
|
|
30215
|
+
// Get size of last block if not skipped
|
|
30216
|
+
let lastBlockSize = 0;
|
|
30217
|
+
if (!skipEnd) {
|
|
30218
|
+
const bsizeOptions = buildOptions(config, {range: {start: endBlock, size: 26}});
|
|
30219
|
+
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30220
|
+
lastBlockSize = bgzBlockSize(abuffer);
|
|
30221
|
+
}
|
|
30222
|
+
|
|
30223
|
+
if (skipStart) {
|
|
30224
|
+
const bsizeOptions = buildOptions(config, {range: {start: startBlock, size: 26}});
|
|
30225
|
+
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30226
|
+
startBlock += bgzBlockSize(abuffer);
|
|
30227
|
+
}
|
|
30228
|
+
|
|
30229
|
+
// Load data for all blocks
|
|
30230
|
+
const loadOptions = buildOptions(config, {
|
|
30231
|
+
range: {
|
|
30232
|
+
start: startBlock,
|
|
30233
|
+
size: endBlock + lastBlockSize - startBlock
|
|
30234
|
+
}
|
|
30235
|
+
});
|
|
30236
|
+
|
|
30237
|
+
//console.log(`${this.config.name} Loaded ${startBlock} - ${endBlock + lastBlockSize} (${(endBlock + lastBlockSize - startBlock) / 1000} kb)`)
|
|
30238
|
+
|
|
30239
|
+
return igvxhr.loadArrayBuffer(config.url, loadOptions)
|
|
30240
|
+
}
|
|
30241
|
+
}
|
|
30242
|
+
|
|
30243
|
+
function findBlockBoundaries(arrayBuffer) {
|
|
30244
|
+
|
|
30245
|
+
const byteLengh = arrayBuffer.byteLength;
|
|
30246
|
+
let offset = 0;
|
|
30247
|
+
const blockBoundaries = [0];
|
|
30248
|
+
while (offset < byteLengh) {
|
|
30249
|
+
//console.log("Cache block " + offset)
|
|
30250
|
+
const ba = new Uint8Array(arrayBuffer, offset);
|
|
30251
|
+
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
30252
|
+
offset += bsize;
|
|
30253
|
+
if (offset < byteLengh) {
|
|
30254
|
+
blockBoundaries.push(offset);
|
|
30255
|
+
}
|
|
30256
|
+
}
|
|
30257
|
+
return blockBoundaries
|
|
30258
|
+
}
|
|
30259
|
+
|
|
30260
|
+
|
|
30261
|
+
/**
|
|
30262
|
+
* Inflate compressed blocks within the data buffer*
|
|
30263
|
+
* @param data
|
|
30264
|
+
* @param startBlock - optional file location for start block. Default == 0
|
|
30265
|
+
* @param endBlock - optional file location for last block to decompress.
|
|
30266
|
+
* @returns {*[]}
|
|
30267
|
+
*/
|
|
30268
|
+
function inflateBlocks(data, startBlock, endBlock) {
|
|
30269
|
+
|
|
30270
|
+
startBlock = startBlock || 0;
|
|
30271
|
+
|
|
30272
|
+
const oBlockList = [];
|
|
30273
|
+
let ptr = startBlock;
|
|
30274
|
+
|
|
30275
|
+
const lim = data.byteLength - 18;
|
|
30276
|
+
while (ptr < lim) {
|
|
30277
|
+
try {
|
|
30278
|
+
//console.log(113873 + ptr)
|
|
30279
|
+
const header = new Uint8Array(data, ptr, 18);
|
|
30280
|
+
const xlen = (header[11] << 8) | (header[10]);
|
|
30281
|
+
const bsize = ((header[17] << 8) | (header[16])); // Total block size, including header, minus 1
|
|
30282
|
+
const start = 12 + xlen + ptr; // Start of CDATA
|
|
30283
|
+
const bytesLeft = data.byteLength - start;
|
|
30284
|
+
const cDataSize = bsize - xlen - 18;
|
|
30285
|
+
|
|
30286
|
+
if (bytesLeft < cDataSize || cDataSize <= 0) {
|
|
30287
|
+
// This is unexpected. Throw error?
|
|
30288
|
+
break
|
|
30289
|
+
}
|
|
30290
|
+
|
|
30291
|
+
const cdata = new Uint8Array(data, start, cDataSize);
|
|
30292
|
+
const unc = inflateRaw(cdata);
|
|
30293
|
+
oBlockList.push(unc);
|
|
30294
|
+
|
|
30295
|
+
if (endBlock === ptr) {
|
|
30296
|
+
break
|
|
30297
|
+
} else {
|
|
30298
|
+
// Advance to next block
|
|
30299
|
+
ptr += bsize + 1;
|
|
30300
|
+
}
|
|
30301
|
+
|
|
30302
|
+
} catch (e) {
|
|
30303
|
+
console.error(e);
|
|
30304
|
+
break
|
|
30305
|
+
}
|
|
30306
|
+
}
|
|
30307
|
+
return oBlockList
|
|
30308
|
+
}
|
|
30309
|
+
|
|
30077
30310
|
/*
|
|
30078
30311
|
* The MIT License (MIT)
|
|
30079
30312
|
*
|
|
@@ -30131,6 +30364,7 @@ class FeatureFileReader {
|
|
|
30131
30364
|
if (this.config.format === "vcf" && !this.config.indexURL) {
|
|
30132
30365
|
console.warn("Warning: index file not specified. The entire vcf file will be loaded.");
|
|
30133
30366
|
}
|
|
30367
|
+
|
|
30134
30368
|
}
|
|
30135
30369
|
|
|
30136
30370
|
async defaultVisibilityWindow() {
|
|
@@ -30188,7 +30422,8 @@ class FeatureFileReader {
|
|
|
30188
30422
|
|
|
30189
30423
|
let dataWrapper;
|
|
30190
30424
|
if (index.tabix) {
|
|
30191
|
-
|
|
30425
|
+
this._blockLoader = new BGZBlockLoader(this.config);
|
|
30426
|
+
dataWrapper = new BGZLineReader(this.config);
|
|
30192
30427
|
} else {
|
|
30193
30428
|
// Tribble
|
|
30194
30429
|
const maxSize = Object.values(index.chrIndex)
|
|
@@ -30274,51 +30509,27 @@ class FeatureFileReader {
|
|
|
30274
30509
|
}
|
|
30275
30510
|
|
|
30276
30511
|
const genome = this.genome;
|
|
30277
|
-
const
|
|
30278
|
-
if (!
|
|
30512
|
+
const chunks = this.index.chunksForRange(refId, start, end);
|
|
30513
|
+
if (!chunks || chunks.length === 0) {
|
|
30279
30514
|
return []
|
|
30280
30515
|
} else {
|
|
30281
30516
|
const allFeatures = [];
|
|
30282
|
-
for (let
|
|
30283
|
-
|
|
30284
|
-
const startPos = block.minv.block;
|
|
30285
|
-
const startOffset = block.minv.offset;
|
|
30286
|
-
const endOffset = block.maxv.offset;
|
|
30287
|
-
let endPos;
|
|
30288
|
-
|
|
30289
|
-
if (tabix) {
|
|
30290
|
-
let lastBlockSize = 0;
|
|
30291
|
-
if (endOffset > 0) {
|
|
30292
|
-
const bsizeOptions = buildOptions(config, {
|
|
30293
|
-
range: {
|
|
30294
|
-
start: block.maxv.block,
|
|
30295
|
-
size: 26
|
|
30296
|
-
}
|
|
30297
|
-
});
|
|
30298
|
-
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30299
|
-
lastBlockSize = bgzBlockSize(abuffer);
|
|
30300
|
-
}
|
|
30301
|
-
endPos = block.maxv.block + lastBlockSize;
|
|
30302
|
-
} else {
|
|
30303
|
-
endPos = block.maxv.block;
|
|
30304
|
-
}
|
|
30305
|
-
|
|
30306
|
-
const options = buildOptions(config, {
|
|
30307
|
-
range: {
|
|
30308
|
-
start: startPos,
|
|
30309
|
-
size: endPos - startPos + 1
|
|
30310
|
-
}
|
|
30311
|
-
});
|
|
30517
|
+
for (let chunk of chunks) {
|
|
30312
30518
|
|
|
30313
30519
|
let inflated;
|
|
30314
30520
|
if (tabix) {
|
|
30315
|
-
|
|
30316
|
-
inflated = unbgzf(data);
|
|
30521
|
+
inflated = await this._blockLoader.getData(chunk.minv.block, chunk.maxv.block);
|
|
30317
30522
|
} else {
|
|
30523
|
+
const options = buildOptions(config, {
|
|
30524
|
+
range: {
|
|
30525
|
+
start: chunk.minv.block,
|
|
30526
|
+
size: chunk.maxv.block - chunk.minv.block + 1
|
|
30527
|
+
}
|
|
30528
|
+
});
|
|
30318
30529
|
inflated = await igvxhr.loadString(config.url, options);
|
|
30319
30530
|
}
|
|
30320
30531
|
|
|
30321
|
-
const slicedData =
|
|
30532
|
+
const slicedData = chunk.minv.offset ? inflated.slice(chunk.minv.offset) : inflated;
|
|
30322
30533
|
const dataWrapper = getDataWrapper(slicedData);
|
|
30323
30534
|
let slicedFeatures = await parser.parseFeatures(dataWrapper);
|
|
30324
30535
|
|
|
@@ -36420,6 +36631,8 @@ class BamReader {
|
|
|
36420
36631
|
this.bamPath = config.url;
|
|
36421
36632
|
this.baiPath = config.indexURL;
|
|
36422
36633
|
BamUtils.setReaderDefaults(this, config);
|
|
36634
|
+
|
|
36635
|
+
this._blockLoader = new BGZBlockLoader(config);
|
|
36423
36636
|
}
|
|
36424
36637
|
|
|
36425
36638
|
async readAlignments(chr, bpStart, bpEnd) {
|
|
@@ -36435,32 +36648,16 @@ class BamReader {
|
|
|
36435
36648
|
} else {
|
|
36436
36649
|
|
|
36437
36650
|
const bamIndex = await this.getIndex();
|
|
36438
|
-
const chunks = bamIndex.
|
|
36651
|
+
const chunks = bamIndex.chunksForRange(chrId, bpStart, bpEnd);
|
|
36439
36652
|
|
|
36440
36653
|
if (!chunks || chunks.length === 0) {
|
|
36441
36654
|
return alignmentContainer
|
|
36442
36655
|
}
|
|
36443
|
-
for (let c of chunks) {
|
|
36444
|
-
|
|
36445
|
-
let lastBlockSize;
|
|
36446
|
-
if (c.maxv.offset === 0) {
|
|
36447
|
-
lastBlockSize = 0; // Don't need to read the last block.
|
|
36448
|
-
} else {
|
|
36449
|
-
const bsizeOptions = buildOptions(this.config, {range: {start: c.maxv.block, size: 26}});
|
|
36450
|
-
const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
|
|
36451
|
-
lastBlockSize = bgzBlockSize(abuffer);
|
|
36452
|
-
}
|
|
36453
|
-
const fetchMin = c.minv.block;
|
|
36454
|
-
const fetchMax = c.maxv.block + lastBlockSize;
|
|
36455
|
-
const range = {start: fetchMin, size: fetchMax - fetchMin + 1};
|
|
36456
36656
|
|
|
36457
|
-
|
|
36458
|
-
|
|
36459
|
-
var ba = unbgzf(compressed); //new Uint8Array(BGZip.unbgzf(compressed)); //, c.maxv.block - c.minv.block + 1));
|
|
36657
|
+
for (let c of chunks) {
|
|
36658
|
+
const ba = await this._blockLoader.getData(c.minv.block, c.maxv.block);
|
|
36460
36659
|
const done = BamUtils.decodeBamRecords(ba, c.minv.offset, alignmentContainer, this.indexToChr, chrId, bpStart, bpEnd, this.filter);
|
|
36461
|
-
|
|
36462
36660
|
if (done) {
|
|
36463
|
-
// console.log(`Loaded ${counter} chunks out of ${chunks.length}`);
|
|
36464
36661
|
break
|
|
36465
36662
|
}
|
|
36466
36663
|
}
|
|
@@ -36477,7 +36674,7 @@ class BamReader {
|
|
|
36477
36674
|
if (index.firstBlockPosition) {
|
|
36478
36675
|
const bsizeOptions = buildOptions(this.config, {range: {start: index.firstBlockPosition, size: 26}});
|
|
36479
36676
|
const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
|
|
36480
|
-
const bsize = bgzBlockSize(abuffer);
|
|
36677
|
+
const bsize = bgzBlockSize$1(abuffer);
|
|
36481
36678
|
len = index.firstBlockPosition + bsize; // Insure we get the complete compressed block containing the header
|
|
36482
36679
|
} else {
|
|
36483
36680
|
len = 64000;
|
|
@@ -40152,7 +40349,9 @@ class BAMTrack extends TrackBase {
|
|
|
40152
40349
|
hoverText(clickState) {
|
|
40153
40350
|
if (true === this.showCoverage && clickState.y >= this.coverageTrack.top && clickState.y < this.coverageTrack.height) {
|
|
40154
40351
|
const clickedObject = this.coverageTrack.getClickedObject(clickState);
|
|
40155
|
-
|
|
40352
|
+
if(clickedObject) {
|
|
40353
|
+
return clickedObject.hoverText()
|
|
40354
|
+
}
|
|
40156
40355
|
}
|
|
40157
40356
|
|
|
40158
40357
|
}
|