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/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.7";
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
- // Represents a BAM index.
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
- blocksForRange(refId, min, max) {
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$1(chunks, lowestOffset)
29470
+ return optimizeChunks(chunks, lowestOffset)
29395
29471
  }
29396
29472
 
29397
29473
  }
@@ -29428,58 +29504,11 @@ class CSIIndex {
29428
29504
 
29429
29505
  }
29430
29506
 
29431
- function optimizeChunks$1(chunks, lowest) {
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
- const MB = 1000000;
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 blocks for a particular genomic range. This method is public so it can be unit-tested.
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: {filePointer, offset}, {maxv: {filePointer, offset}}
29638
+ * @param return an array of objects representing chunks (file spans) {minv: {block, offset}, {maxv: {block, offset}}
29610
29639
  */
29611
- blocksForRange(refId, min, max) {
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, bin: bin});
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
- let lowest = null;
29639
- const minLin = Math.min(min >> 14, nintv - 1);
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 < maxLin; i++) {
29676
+ for (let i = minLin; i <= maxLin; i++) {
29642
29677
  const vp = ba.linearIndex[i];
29643
29678
  if (vp) {
29644
- // todo -- I think, but am not sure, that the values in the linear index have to be in increasing order. So the first non-null should be minimum
29645
- if (!lowest || vp.isLessThan(lowest)) {
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
- blocksForRange(queryChr, min, max) { //function (refId, min, max) {
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
- class BGZipLineReader {
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
- dataWrapper = new BGZipLineReader(this.config);
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 blocks = this.index.blocksForRange(refId, start, end);
30278
- if (!blocks || blocks.length === 0) {
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 block of blocks) {
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
- const data = await igvxhr.loadArrayBuffer(config.url, options);
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 = startOffset ? inflated.slice(startOffset) : inflated;
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.blocksForRange(chrId, bpStart, bpEnd);
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
- const compressed = await igvxhr.loadArrayBuffer(this.bamPath, buildOptions(this.config, {range: range}));
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
- return clickedObject.hoverText()
40352
+ if(clickedObject) {
40353
+ return clickedObject.hoverText()
40354
+ }
40156
40355
  }
40157
40356
 
40158
40357
  }