igv 2.13.7 → 2.13.9

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.js CHANGED
@@ -13966,7 +13966,7 @@
13966
13966
  const {
13967
13967
  Inflate,
13968
13968
  inflate: inflate$3,
13969
- inflateRaw,
13969
+ inflateRaw: inflateRaw$2,
13970
13970
  ungzip: ungzip$2
13971
13971
  } = inflate_1$1;
13972
13972
  var Deflate_1 = Deflate;
@@ -13975,7 +13975,7 @@
13975
13975
  var gzip_1 = gzip;
13976
13976
  var Inflate_1 = Inflate;
13977
13977
  var inflate_1 = inflate$3;
13978
- var inflateRaw_1 = inflateRaw;
13978
+ var inflateRaw_1 = inflateRaw$2;
13979
13979
  var ungzip_1 = ungzip$2;
13980
13980
  var constants_1 = constants$2;
13981
13981
  var pako = {
@@ -14008,7 +14008,7 @@
14008
14008
 
14009
14009
  pako.deflateRaw;
14010
14010
  pako.deflate;
14011
- pako.inflateRaw;
14011
+ const inflateRaw = pako.inflateRaw;
14012
14012
  const inflate = pako.inflate;
14013
14013
  pako.gzip;
14014
14014
  const FEXTRA = 4; // gzip spec F.EXTRA flag
@@ -14080,7 +14080,7 @@
14080
14080
  return out;
14081
14081
  }
14082
14082
  }
14083
- function bgzBlockSize(data) {
14083
+ function bgzBlockSize$1(data) {
14084
14084
  const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
14085
14085
  const bsize = (ba[17] << 8 | ba[16]) + 1;
14086
14086
  return bsize;
@@ -16829,10 +16829,7 @@
16829
16829
  var rgb = this.hsvToRgb(this.hue, saturation, value);
16830
16830
  return "#" + this.padHex(rgb[0].toString(16)) + this.padHex(rgb[1].toString(16)) + this.padHex(rgb[2].toString(16));
16831
16831
  };
16832
- const randomColorGenerator = new RandomColorGenerator();
16833
- function randomColor() {
16834
- return randomColorGenerator.get();
16835
- }
16832
+ new RandomColorGenerator();
16836
16833
  function randomRGB$1(min, max) {
16837
16834
  min = IGVMath.clamp(min, 0, 255);
16838
16835
  max = IGVMath.clamp(max, 0, 255);
@@ -18865,7 +18862,7 @@
18865
18862
 
18866
18863
  const doAutoscale = function (features) {
18867
18864
  var min, max;
18868
- if (features.length > 0) {
18865
+ if (features && features.length > 0) {
18869
18866
  min = Number.MAX_VALUE;
18870
18867
  max = -Number.MAX_VALUE;
18871
18868
  features.forEach(function (f) {
@@ -21939,7 +21936,7 @@
21939
21936
  }
21940
21937
  };
21941
21938
 
21942
- const _version = "2.13.7";
21939
+ const _version = "2.13.9";
21943
21940
  function version$1() {
21944
21941
  return _version;
21945
21942
  }
@@ -26462,12 +26459,81 @@
26462
26459
  isGreaterThan(vp) {
26463
26460
  return this.block > vp.block || this.block === vp.block && this.offset > vp.offset;
26464
26461
  }
26462
+ isEqualTo(vp) {
26463
+ return this.block === vp.block && this.offset === vp.offset;
26464
+ }
26465
26465
  print() {
26466
26466
  return "" + this.block + ":" + this.offset;
26467
26467
  }
26468
26468
  }
26469
26469
 
26470
- // Represents a BAM index.
26470
+ function optimizeChunks(chunks, lowest) {
26471
+ if (chunks.length === 0) return chunks;
26472
+ chunks.sort(function (c0, c1) {
26473
+ const dif = c0.minv.block - c1.minv.block;
26474
+ if (dif !== 0) {
26475
+ return dif;
26476
+ } else {
26477
+ return c0.minv.offset - c1.minv.offset;
26478
+ }
26479
+ });
26480
+ if (chunks.length <= 1) {
26481
+ return chunks;
26482
+ }
26483
+
26484
+ // console.log("Before trimming " + chunks.length)
26485
+ // for (let c of chunks) {
26486
+ // console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
26487
+ // }
26488
+
26489
+ if (lowest) {
26490
+ chunks = chunks.filter(c => c.maxv.isGreaterThan(lowest));
26491
+ }
26492
+
26493
+ // console.log("Before merging " + chunks.length)
26494
+ // for (let c of chunks) {
26495
+ // console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
26496
+ // }
26497
+
26498
+ const mergedChunks = [];
26499
+ let lastChunk;
26500
+ for (let chunk of chunks) {
26501
+ if (!lastChunk) {
26502
+ mergedChunks.push(chunk);
26503
+ lastChunk = chunk;
26504
+ } else {
26505
+ if (canMerge(lastChunk, chunk)) {
26506
+ if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
26507
+ lastChunk.maxv = chunk.maxv;
26508
+ }
26509
+ } else {
26510
+ mergedChunks.push(chunk);
26511
+ lastChunk = chunk;
26512
+ }
26513
+ }
26514
+ }
26515
+
26516
+ // console.log("After merging " + mergedChunks.length)
26517
+ // for (let c of mergedChunks) {
26518
+ // console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
26519
+ // }
26520
+
26521
+ return mergedChunks;
26522
+ }
26523
+
26524
+ /**
26525
+ * Merge 2 blocks if the file position gap between them is < 16 kb, and the total size is < ~5 mb
26526
+ * @param chunk1
26527
+ * @param chunk2
26528
+ * @returns {boolean|boolean}
26529
+ */
26530
+ function canMerge(chunk1, chunk2) {
26531
+ const gap = chunk2.minv.block - chunk1.maxv.block;
26532
+ const sizeEstimate = chunk1.maxv.block - chunk1.minv.block;
26533
+ return gap < 65000 && sizeEstimate < 5000000;
26534
+ }
26535
+
26536
+ // Represents a CSI Bam or Tabix index
26471
26537
  const CSI1_MAGIC$1 = 21582659; // CSI\1
26472
26538
  const CSI2_MAGIC$1 = 38359875; // CSI\2
26473
26539
 
@@ -26579,7 +26645,7 @@
26579
26645
  * @param max genomic end position
26580
26646
  * @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
26581
26647
  */
26582
- blocksForRange(refId, min, max) {
26648
+ chunksForRange(refId, min, max) {
26583
26649
  const ba = this.indices[refId];
26584
26650
  if (!ba) {
26585
26651
  return [];
@@ -26605,7 +26671,7 @@
26605
26671
  }
26606
26672
  }
26607
26673
  const lowestOffset = ba.loffset[overlappingBins[0]];
26608
- return optimizeChunks$1(chunks, lowestOffset);
26674
+ return optimizeChunks(chunks, lowestOffset);
26609
26675
  }
26610
26676
  }
26611
26677
 
@@ -26637,48 +26703,10 @@
26637
26703
  return ((1 << (this.depth + 1) * 3) - 1) / 7;
26638
26704
  }
26639
26705
  }
26640
- function optimizeChunks$1(chunks, lowest) {
26641
- const mergedChunks = [];
26642
- let lastChunk = null;
26643
- if (chunks.length === 0) return chunks;
26644
- chunks.sort(function (c0, c1) {
26645
- const dif = c0.minv.block - c1.minv.block;
26646
- if (dif !== 0) {
26647
- return dif;
26648
- } else {
26649
- return c0.minv.offset - c1.minv.offset;
26650
- }
26651
- });
26652
- chunks.forEach(function (chunk) {
26653
- if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
26654
- if (lastChunk === null) {
26655
- mergedChunks.push(chunk);
26656
- lastChunk = chunk;
26657
- } else {
26658
- if (canMerge$1(lastChunk, chunk)) {
26659
- if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
26660
- lastChunk.maxv = chunk.maxv;
26661
- }
26662
- } else {
26663
- mergedChunks.push(chunk);
26664
- lastChunk = chunk;
26665
- }
26666
- }
26667
- }
26668
- });
26669
- return mergedChunks;
26670
- }
26671
- function canMerge$1(chunk1, chunk2) {
26672
- return chunk2.minv.block - chunk1.maxv.block < 65000 && chunk2.maxv.block - chunk1.minv.block < 5000000;
26673
- // lastChunk.minv.block === lastChunk.maxv.block &&
26674
- // lastChunk.maxv.block === chunk.minv.block &&
26675
- // chunk.minv.block === chunk.maxv.block
26676
- }
26677
26706
 
26678
- // Represents a BAM index.
26707
+ // Represents a BAM or Tabix index.
26679
26708
  const BAI_MAGIC$1 = 21578050;
26680
26709
  const TABIX_MAGIC$1 = 21578324;
26681
- const MB = 1000000;
26682
26710
  async function parseBamIndex(arrayBuffer, genome) {
26683
26711
  const index = new BamIndex();
26684
26712
  await index.parse(arrayBuffer, false, genome);
@@ -26780,22 +26808,27 @@
26780
26808
  }
26781
26809
 
26782
26810
  /**
26783
- * Fetch blocks for a particular genomic range. This method is public so it can be unit-tested.
26811
+ * Fetch chunks for a particular genomic range. This method is public so it can be unit-tested.
26784
26812
  *
26785
26813
  * @param refId the sequence dictionary index of the chromosome
26786
26814
  * @param min genomic start position
26787
26815
  * @param max genomic end position
26788
- * @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
26816
+ * @param return an array of objects representing chunks (file spans) {minv: {block, offset}, {maxv: {block, offset}}
26789
26817
  */
26790
- blocksForRange(refId, min, max) {
26818
+ chunksForRange(refId, min, max) {
26791
26819
  const bam = this;
26792
26820
  const ba = bam.indices[refId];
26793
26821
  if (!ba) {
26794
26822
  return [];
26795
26823
  } else {
26796
26824
  const overlappingBins = reg2bins(min, max); // List of bin #s that overlap min, max
26797
- const chunks = [];
26798
26825
 
26826
+ //console.log("bin ranges")
26827
+ //for(let b of overlappingBins) {
26828
+ // console.log(`${b[0]} - ${b[1]}`)
26829
+ //}
26830
+
26831
+ const chunks = [];
26799
26832
  // Find chunks in overlapping bins. Leaf bins (< 4681) are not pruned
26800
26833
  for (let binRange of overlappingBins) {
26801
26834
  for (let bin = binRange[0]; bin <= binRange[1]; bin++) {
@@ -26806,8 +26839,7 @@
26806
26839
  const ce = c[1];
26807
26840
  chunks.push({
26808
26841
  minv: cs,
26809
- maxv: ce,
26810
- bin: bin
26842
+ maxv: ce
26811
26843
  });
26812
26844
  }
26813
26845
  }
@@ -26816,65 +26848,20 @@
26816
26848
 
26817
26849
  // Use the linear index to find minimum file position of chunks that could contain alignments in the region
26818
26850
  const nintv = ba.linearIndex.length;
26819
- let lowest = null;
26820
- const minLin = Math.min(min >> 14, nintv - 1);
26851
+ let lowest;
26852
+ const minLin = Math.min(min >> 14, nintv - 1); // i.e. min / 16384
26821
26853
  const maxLin = Math.min(max >> 14, nintv - 1);
26822
- for (let i = minLin; i < maxLin; i++) {
26854
+ for (let i = minLin; i <= maxLin; i++) {
26823
26855
  const vp = ba.linearIndex[i];
26824
26856
  if (vp) {
26825
- // 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
26826
- if (!lowest || vp.isLessThan(lowest)) {
26827
- lowest = vp;
26828
- }
26857
+ lowest = vp; // lowest file offset that contains alignments overlapping (min, max)
26858
+ break;
26829
26859
  }
26830
26860
  }
26831
26861
  return optimizeChunks(chunks, lowest);
26832
26862
  }
26833
26863
  }
26834
26864
  }
26835
- function optimizeChunks(chunks, lowest) {
26836
- const mergedChunks = [];
26837
- let lastChunk = null;
26838
- if (chunks.length === 0) return chunks;
26839
- chunks.sort(function (c0, c1) {
26840
- const dif = c0.minv.block - c1.minv.block;
26841
- if (dif !== 0) {
26842
- return dif;
26843
- } else {
26844
- return c0.minv.offset - c1.minv.offset;
26845
- }
26846
- });
26847
- chunks.forEach(function (chunk) {
26848
- if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
26849
- if (lastChunk === null) {
26850
- mergedChunks.push(chunk);
26851
- lastChunk = chunk;
26852
- } else {
26853
- if (canMerge(lastChunk, chunk)) {
26854
- if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
26855
- lastChunk.maxv = chunk.maxv;
26856
- }
26857
- } else {
26858
- mergedChunks.push(chunk);
26859
- lastChunk = chunk;
26860
- }
26861
- }
26862
- }
26863
- });
26864
- return mergedChunks;
26865
- }
26866
-
26867
- /**
26868
- * Merge 2 blocks if the gap between them is < 1kb and the total resulting size < 100mb
26869
- * @param chunk1
26870
- * @param chunk2
26871
- * @returns {boolean|boolean}
26872
- */
26873
- function canMerge(chunk1, chunk2) {
26874
- const gap = chunk2.minv.block - chunk1.maxv.block;
26875
- const total = chunk2.maxv.block - chunk1.minv.block;
26876
- return gap < 30000 && total < 10 * MB;
26877
- }
26878
26865
 
26879
26866
  /**
26880
26867
  * Calculate the list of bins that overlap with region [beg, end]
@@ -27006,7 +26993,7 @@
27006
26993
  * @param min genomic start position
27007
26994
  * @param max genomic end position
27008
26995
  */
27009
- blocksForRange(queryChr, min, max) {
26996
+ chunksForRange(queryChr, min, max) {
27010
26997
  const chrIdx = this.chrIndex[queryChr];
27011
26998
  if (chrIdx) {
27012
26999
  const blocks = chrIdx.blocks;
@@ -27166,7 +27153,12 @@
27166
27153
  }
27167
27154
  }
27168
27155
 
27169
- class BGZipLineReader {
27156
+ /**
27157
+ * Class to iterate line-by-line over a BGZipped text file. This class is useful for iterating from the start of
27158
+ * the file. Not useful for indexed queries.
27159
+ */
27160
+
27161
+ class BGZLineReader {
27170
27162
  constructor(config) {
27171
27163
  this.config = config;
27172
27164
  this.filePtr = 0;
@@ -27206,7 +27198,7 @@
27206
27198
  }
27207
27199
  });
27208
27200
  const abuffer = await igvxhr.loadArrayBuffer(this.config.url, bsizeOptions);
27209
- const bufferSize = bgzBlockSize(abuffer);
27201
+ const bufferSize = bgzBlockSize$1(abuffer);
27210
27202
  //console.log(`next block ${this.filePtr} ${bufferSize}`);
27211
27203
 
27212
27204
  if (bufferSize === 0) {
@@ -27231,6 +27223,244 @@
27231
27223
  }
27232
27224
  }
27233
27225
 
27226
+ function concatenateArrayBuffers(arrayBuffers) {
27227
+ if (arrayBuffers.length === 1) {
27228
+ return arrayBuffers[0];
27229
+ }
27230
+ let len = 0;
27231
+ for (const b of arrayBuffers) {
27232
+ len += b.byteLength;
27233
+ }
27234
+ const c = new Uint8Array(len);
27235
+ let offset = 0;
27236
+ for (const b of arrayBuffers) {
27237
+ c.set(new Uint8Array(b), offset);
27238
+ offset += b.byteLength;
27239
+ }
27240
+ return c.buffer;
27241
+ }
27242
+
27243
+ /**
27244
+ * Return the block size for the data buffer.
27245
+ * @param data
27246
+ * @returns {number}
27247
+ */
27248
+ const bgzBlockSize = data => {
27249
+ const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
27250
+ const bsize = (ba[17] << 8 | ba[16]) + 1;
27251
+ return bsize;
27252
+ };
27253
+ class BGZBlockLoader {
27254
+ constructor(config) {
27255
+ this.config = config;
27256
+ this.cacheBlocks = false != config.cacheBlocks; // Default to true
27257
+ this.cache = undefined;
27258
+ }
27259
+
27260
+ /**
27261
+ * Return inflated data from startBlock through endBlock as an UInt8Array
27262
+ *
27263
+ * @param startBlock
27264
+ * @param endBlock
27265
+ * @returns {Promise<Uint8Array>}
27266
+ */
27267
+ async getData(startBlock, endBlock) {
27268
+ const blocks = await this.getInflatedBlocks(startBlock, endBlock);
27269
+ if (blocks.length === 1) {
27270
+ return blocks[0];
27271
+ }
27272
+ let len = 0;
27273
+ for (const b of blocks) {
27274
+ len += b.byteLength;
27275
+ }
27276
+ const c = new Uint8Array(len);
27277
+ let offset = 0;
27278
+ for (const b of blocks) {
27279
+ c.set(b, offset);
27280
+ offset += b.byteLength;
27281
+ }
27282
+ return c;
27283
+ }
27284
+
27285
+ /**
27286
+ * Return the inflated data for the specified blocks as an array of Uint8Arrays. This method is public so
27287
+ * it can be unit tested. *
27288
+ * @param startBlock
27289
+ * @param endBlock
27290
+ * @returns {Promise<*[Uint8Array]>}
27291
+ */
27292
+ async getInflatedBlocks(startBlock, endBlock) {
27293
+ if (!this.cacheBlocks) {
27294
+ const buffer = await this.loadBLockData(startBlock, endBlock);
27295
+ return inflateBlocks(buffer);
27296
+ } else {
27297
+ const c = this.cache;
27298
+ if (c && c.startBlock <= startBlock && c.endBlock >= endBlock) {
27299
+ //console.log("Complete overlap")
27300
+ const startOffset = startBlock - c.startBlock;
27301
+ const endOffset = endBlock - c.startBlock;
27302
+ return inflateBlocks(c.buffer, startOffset, endOffset);
27303
+ // Don't update cache, still valid
27304
+ } else {
27305
+ let buffer;
27306
+ if (!c || c.startBlock > endBlock || c.endBlock < startBlock) {
27307
+ // no overlap with cache
27308
+ buffer = await this.loadBLockData(startBlock, endBlock);
27309
+ } else {
27310
+ //console.log("Some overlap")
27311
+ const arrayBuffers = [];
27312
+
27313
+ // Load blocks preceding cache start, if any
27314
+ if (startBlock < c.startBlock) {
27315
+ // load first blocks
27316
+ const startBuffer = await this.loadBLockData(startBlock, c.startBlock, {
27317
+ skipEnd: true
27318
+ });
27319
+ arrayBuffers.push(startBuffer);
27320
+ }
27321
+
27322
+ // Slice cached buffer as needed
27323
+ let cachedBuffer;
27324
+ if (startBlock <= c.startBlock && endBlock >= c.endBlock) {
27325
+ cachedBuffer = c.buffer;
27326
+ } else {
27327
+ const start = Math.max(0, startBlock - c.startBlock);
27328
+ let end;
27329
+ if (endBlock >= c.endBlock) {
27330
+ end = c.buffer.byteLength;
27331
+ } else {
27332
+ // We need to find the byte position of the end of "endBlock"
27333
+ const boundaries = findBlockBoundaries(c.buffer);
27334
+ for (let i = 0; i < boundaries.length - 1; i++) {
27335
+ if (c.startBlock + boundaries[i] === endBlock) {
27336
+ end = boundaries[i + 1];
27337
+ break;
27338
+ }
27339
+ }
27340
+ // Do something if end not found
27341
+ }
27342
+
27343
+ cachedBuffer = c.buffer.slice(start, end);
27344
+ }
27345
+ arrayBuffers.push(cachedBuffer);
27346
+
27347
+ // Load end blocks, if any
27348
+ if (endBlock > c.endBlock) {
27349
+ const endBuffer = await this.loadBLockData(c.endBlock, endBlock, {
27350
+ skipStart: true
27351
+ });
27352
+ arrayBuffers.push(endBuffer);
27353
+ }
27354
+ buffer = concatenateArrayBuffers(arrayBuffers);
27355
+ }
27356
+ this.cache = {
27357
+ startBlock,
27358
+ endBlock,
27359
+ buffer
27360
+ };
27361
+ return inflateBlocks(buffer);
27362
+ }
27363
+ }
27364
+ }
27365
+ async loadBLockData(startBlock, endBlock, options) {
27366
+ const config = this.config;
27367
+ const skipStart = options && options.skipStart;
27368
+ const skipEnd = options && options.skipEnd;
27369
+
27370
+ // Get size of last block if not skipped
27371
+ let lastBlockSize = 0;
27372
+ if (!skipEnd) {
27373
+ const bsizeOptions = buildOptions(config, {
27374
+ range: {
27375
+ start: endBlock,
27376
+ size: 26
27377
+ }
27378
+ });
27379
+ const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
27380
+ lastBlockSize = bgzBlockSize(abuffer);
27381
+ }
27382
+ if (skipStart) {
27383
+ const bsizeOptions = buildOptions(config, {
27384
+ range: {
27385
+ start: startBlock,
27386
+ size: 26
27387
+ }
27388
+ });
27389
+ const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
27390
+ startBlock += bgzBlockSize(abuffer);
27391
+ }
27392
+
27393
+ // Load data for all blocks
27394
+ const loadOptions = buildOptions(config, {
27395
+ range: {
27396
+ start: startBlock,
27397
+ size: endBlock + lastBlockSize - startBlock
27398
+ }
27399
+ });
27400
+
27401
+ //console.log(`${this.config.name} Loaded ${startBlock} - ${endBlock + lastBlockSize} (${(endBlock + lastBlockSize - startBlock) / 1000} kb)`)
27402
+
27403
+ return igvxhr.loadArrayBuffer(config.url, loadOptions);
27404
+ }
27405
+ }
27406
+ function findBlockBoundaries(arrayBuffer) {
27407
+ const byteLengh = arrayBuffer.byteLength;
27408
+ let offset = 0;
27409
+ const blockBoundaries = [0];
27410
+ while (offset < byteLengh) {
27411
+ //console.log("Cache block " + offset)
27412
+ const ba = new Uint8Array(arrayBuffer, offset);
27413
+ const bsize = (ba[17] << 8 | ba[16]) + 1;
27414
+ offset += bsize;
27415
+ if (offset < byteLengh) {
27416
+ blockBoundaries.push(offset);
27417
+ }
27418
+ }
27419
+ return blockBoundaries;
27420
+ }
27421
+
27422
+ /**
27423
+ * Inflate compressed blocks within the data buffer*
27424
+ * @param data
27425
+ * @param startBlock - optional file location for start block. Default == 0
27426
+ * @param endBlock - optional file location for last block to decompress.
27427
+ * @returns {*[]}
27428
+ */
27429
+ function inflateBlocks(data, startBlock, endBlock) {
27430
+ startBlock = startBlock || 0;
27431
+ const oBlockList = [];
27432
+ let ptr = startBlock;
27433
+ const lim = data.byteLength - 18;
27434
+ while (ptr < lim) {
27435
+ try {
27436
+ //console.log(113873 + ptr)
27437
+ const header = new Uint8Array(data, ptr, 18);
27438
+ const xlen = header[11] << 8 | header[10];
27439
+ const bsize = header[17] << 8 | header[16]; // Total block size, including header, minus 1
27440
+ const start = 12 + xlen + ptr; // Start of CDATA
27441
+ const bytesLeft = data.byteLength - start;
27442
+ const cDataSize = bsize - xlen - 18;
27443
+ if (bytesLeft < cDataSize || cDataSize <= 0) {
27444
+ // This is unexpected. Throw error?
27445
+ break;
27446
+ }
27447
+ const cdata = new Uint8Array(data, start, cDataSize);
27448
+ const unc = inflateRaw(cdata);
27449
+ oBlockList.push(unc);
27450
+ if (endBlock === ptr) {
27451
+ break;
27452
+ } else {
27453
+ // Advance to next block
27454
+ ptr += bsize + 1;
27455
+ }
27456
+ } catch (e) {
27457
+ console.error(e);
27458
+ break;
27459
+ }
27460
+ }
27461
+ return oBlockList;
27462
+ }
27463
+
27234
27464
  /*
27235
27465
  * The MIT License (MIT)
27236
27466
  *
@@ -27332,7 +27562,8 @@
27332
27562
  }
27333
27563
  let dataWrapper;
27334
27564
  if (index.tabix) {
27335
- dataWrapper = new BGZipLineReader(this.config);
27565
+ this._blockLoader = new BGZBlockLoader(this.config);
27566
+ dataWrapper = new BGZLineReader(this.config);
27336
27567
  } else {
27337
27568
  // Tribble
27338
27569
  const maxSize = Object.values(index.chrIndex).flatMap(chr => chr.blocks).map(block => block.max).reduce((previous, current) => Math.min(previous, current), Number.MAX_SAFE_INTEGER);
@@ -27408,46 +27639,25 @@
27408
27639
  return [];
27409
27640
  }
27410
27641
  const genome = this.genome;
27411
- const blocks = this.index.blocksForRange(refId, start, end);
27412
- if (!blocks || blocks.length === 0) {
27642
+ const chunks = this.index.chunksForRange(refId, start, end);
27643
+ if (!chunks || chunks.length === 0) {
27413
27644
  return [];
27414
27645
  } else {
27415
27646
  const allFeatures = [];
27416
- for (let block of blocks) {
27417
- const startPos = block.minv.block;
27418
- const startOffset = block.minv.offset;
27419
- const endOffset = block.maxv.offset;
27420
- let endPos;
27421
- if (tabix) {
27422
- let lastBlockSize = 0;
27423
- if (endOffset > 0) {
27424
- const bsizeOptions = buildOptions(config, {
27425
- range: {
27426
- start: block.maxv.block,
27427
- size: 26
27428
- }
27429
- });
27430
- const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
27431
- lastBlockSize = bgzBlockSize(abuffer);
27432
- }
27433
- endPos = block.maxv.block + lastBlockSize;
27434
- } else {
27435
- endPos = block.maxv.block;
27436
- }
27437
- const options = buildOptions(config, {
27438
- range: {
27439
- start: startPos,
27440
- size: endPos - startPos + 1
27441
- }
27442
- });
27647
+ for (let chunk of chunks) {
27443
27648
  let inflated;
27444
27649
  if (tabix) {
27445
- const data = await igvxhr.loadArrayBuffer(config.url, options);
27446
- inflated = unbgzf(data);
27650
+ inflated = await this._blockLoader.getData(chunk.minv.block, chunk.maxv.block);
27447
27651
  } else {
27652
+ const options = buildOptions(config, {
27653
+ range: {
27654
+ start: chunk.minv.block,
27655
+ size: chunk.maxv.block - chunk.minv.block + 1
27656
+ }
27657
+ });
27448
27658
  inflated = await igvxhr.loadString(config.url, options);
27449
27659
  }
27450
- const slicedData = startOffset ? inflated.slice(startOffset) : inflated;
27660
+ const slicedData = chunk.minv.offset ? inflated.slice(chunk.minv.offset) : inflated;
27451
27661
  const dataWrapper = getDataWrapper(slicedData);
27452
27662
  let slicedFeatures = await parser.parseFeatures(dataWrapper);
27453
27663
 
@@ -29873,6 +30083,7 @@
29873
30083
  var documentAll$2 = typeof document == 'object' && document.all;
29874
30084
 
29875
30085
  // https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot
30086
+ // eslint-disable-next-line unicorn/no-typeof-undefined -- required for testing
29876
30087
  var IS_HTMLDDA = typeof documentAll$2 == 'undefined' && documentAll$2 !== undefined;
29877
30088
  var documentAll_1 = {
29878
30089
  all: documentAll$2,
@@ -30127,10 +30338,10 @@
30127
30338
  (module.exports = function (key, value) {
30128
30339
  return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
30129
30340
  })('versions', []).push({
30130
- version: '3.26.1',
30341
+ version: '3.27.1',
30131
30342
  mode: 'global',
30132
30343
  copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',
30133
- license: 'https://github.com/zloirock/core-js/blob/v3.26.1/LICENSE',
30344
+ license: 'https://github.com/zloirock/core-js/blob/v3.27.1/LICENSE',
30134
30345
  source: 'https://github.com/zloirock/core-js'
30135
30346
  });
30136
30347
  });
@@ -33368,6 +33579,7 @@
33368
33579
  this.bamPath = config.url;
33369
33580
  this.baiPath = config.indexURL;
33370
33581
  BamUtils.setReaderDefaults(this, config);
33582
+ this._blockLoader = new BGZBlockLoader(config);
33371
33583
  }
33372
33584
  async readAlignments(chr, bpStart, bpEnd) {
33373
33585
  const chrToIndex = await this.getChrIndex();
@@ -33378,37 +33590,14 @@
33378
33590
  return alignmentContainer;
33379
33591
  } else {
33380
33592
  const bamIndex = await this.getIndex();
33381
- const chunks = bamIndex.blocksForRange(chrId, bpStart, bpEnd);
33593
+ const chunks = bamIndex.chunksForRange(chrId, bpStart, bpEnd);
33382
33594
  if (!chunks || chunks.length === 0) {
33383
33595
  return alignmentContainer;
33384
33596
  }
33385
33597
  for (let c of chunks) {
33386
- let lastBlockSize;
33387
- if (c.maxv.offset === 0) {
33388
- lastBlockSize = 0; // Don't need to read the last block.
33389
- } else {
33390
- const bsizeOptions = buildOptions(this.config, {
33391
- range: {
33392
- start: c.maxv.block,
33393
- size: 26
33394
- }
33395
- });
33396
- const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
33397
- lastBlockSize = bgzBlockSize(abuffer);
33398
- }
33399
- const fetchMin = c.minv.block;
33400
- const fetchMax = c.maxv.block + lastBlockSize;
33401
- const range = {
33402
- start: fetchMin,
33403
- size: fetchMax - fetchMin + 1
33404
- };
33405
- const compressed = await igvxhr.loadArrayBuffer(this.bamPath, buildOptions(this.config, {
33406
- range: range
33407
- }));
33408
- var ba = unbgzf(compressed); //new Uint8Array(BGZip.unbgzf(compressed)); //, c.maxv.block - c.minv.block + 1));
33598
+ const ba = await this._blockLoader.getData(c.minv.block, c.maxv.block);
33409
33599
  const done = BamUtils.decodeBamRecords(ba, c.minv.offset, alignmentContainer, this.indexToChr, chrId, bpStart, bpEnd, this.filter);
33410
33600
  if (done) {
33411
- // console.log(`Loaded ${counter} chunks out of ${chunks.length}`);
33412
33601
  break;
33413
33602
  }
33414
33603
  }
@@ -33429,7 +33618,7 @@
33429
33618
  }
33430
33619
  });
33431
33620
  const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
33432
- const bsize = bgzBlockSize(abuffer);
33621
+ const bsize = bgzBlockSize$1(abuffer);
33433
33622
  len = index.firstBlockPosition + bsize; // Insure we get the complete compressed block containing the header
33434
33623
  } else {
33435
33624
  len = 64000;
@@ -33967,7 +34156,7 @@
33967
34156
  var clear = global$1.clearImmediate;
33968
34157
  var process$1 = global$1.process;
33969
34158
  var Dispatch = global$1.Dispatch;
33970
- var Function$1 = global$1.Function;
34159
+ var Function$2 = global$1.Function;
33971
34160
  var MessageChannel$1 = global$1.MessageChannel;
33972
34161
  var String$1 = global$1.String;
33973
34162
  var counter = 0;
@@ -34002,7 +34191,7 @@
34002
34191
  if (!set || !clear) {
34003
34192
  set = function setImmediate(handler) {
34004
34193
  validateArgumentsLength(arguments.length, 1);
34005
- var fn = isCallable(handler) ? handler : Function$1(handler);
34194
+ var fn = isCallable(handler) ? handler : Function$2(handler);
34006
34195
  var args = arraySlice(arguments, 1);
34007
34196
  queue[++counter] = function () {
34008
34197
  functionApply(fn, undefined, args);
@@ -34068,7 +34257,36 @@
34068
34257
  clearImmediate: clearImmediate
34069
34258
  });
34070
34259
 
34071
- var setImmediate = task.set;
34260
+ /* global Bun -- Deno case */
34261
+ var engineIsBun = typeof Bun == 'function' && Bun && typeof Bun.version == 'string';
34262
+
34263
+ var Function$1 = global$1.Function;
34264
+ // dirty IE9- and Bun 0.3.0- checks
34265
+ var WRAP = /MSIE .\./.test(engineUserAgent) || engineIsBun && function () {
34266
+ var version = global$1.Bun.version.split('.');
34267
+ return version.length < 3 || version[0] == 0 && (version[1] < 3 || version[1] == 3 && version[2] == 0);
34268
+ }();
34269
+
34270
+ // IE9- / Bun 0.3.0- setTimeout / setInterval / setImmediate additional parameters fix
34271
+ // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
34272
+ // https://github.com/oven-sh/bun/issues/1633
34273
+ var schedulersFix = function (scheduler, hasTimeArg) {
34274
+ var firstParamIndex = hasTimeArg ? 2 : 1;
34275
+ return WRAP ? function (handler, timeout /* , ...arguments */) {
34276
+ var boundArgs = validateArgumentsLength(arguments.length, 1) > firstParamIndex;
34277
+ var fn = isCallable(handler) ? handler : Function$1(handler);
34278
+ var params = boundArgs ? arraySlice(arguments, firstParamIndex) : [];
34279
+ var callback = boundArgs ? function () {
34280
+ functionApply(fn, this, params);
34281
+ } : fn;
34282
+ return hasTimeArg ? scheduler(callback, timeout) : scheduler(callback);
34283
+ } : scheduler;
34284
+ };
34285
+
34286
+ var setTask = task.set;
34287
+
34288
+ // https://github.com/oven-sh/bun/issues/1633
34289
+ var setImmediate = global$1.setImmediate ? schedulersFix(setTask, false) : setTask;
34072
34290
 
34073
34291
  // `setImmediate` method
34074
34292
  // http://w3c.github.io/setImmediate/#si-setImmediate
@@ -50411,7 +50629,9 @@
50411
50629
  hoverText(clickState) {
50412
50630
  if (true === this.showCoverage && clickState.y >= this.coverageTrack.top && clickState.y < this.coverageTrack.height) {
50413
50631
  const clickedObject = this.coverageTrack.getClickedObject(clickState);
50414
- return clickedObject.hoverText();
50632
+ if (clickedObject) {
50633
+ return clickedObject.hoverText();
50634
+ }
50415
50635
  }
50416
50636
  }
50417
50637
  menuItemList() {
@@ -52753,7 +52973,14 @@
52753
52973
  value: max
52754
52974
  }];
52755
52975
  } else {
52756
- allFeatures = FeatureUtils.findOverlapping(visibleViewport.featureCache.features, start, end);
52976
+ const viewFeatures = FeatureUtils.findOverlapping(visibleViewport.featureCache.features, start, end);
52977
+ if (!allFeatures) {
52978
+ allFeatures = viewFeatures;
52979
+ } else {
52980
+ for (let f of viewFeatures) {
52981
+ allFeatures.push(f);
52982
+ }
52983
+ }
52757
52984
  }
52758
52985
  }
52759
52986
  }
@@ -56669,21 +56896,16 @@
56669
56896
  * Colors used for coding omosomes
56670
56897
  */
56671
56898
 
56672
- const Colors = {
56899
+ const GWASColors = {
56673
56900
  "X": "rgb(204, 153, 0)",
56674
56901
  "Y": "rgb(153, 204, 0)",
56675
56902
  "Un": "darkGray)",
56676
56903
  "1": "rgb(80, 80, 255)",
56677
- //"1": Color.red);
56678
- "I": "rgb(139, 155, 187)",
56679
56904
  "2": "rgb(206, 61, 50)",
56680
- "II": "rgb(206, 61, 50)",
56681
56905
  "2a": "rgb(210, 65, 55)",
56682
56906
  "2b": "rgb(215, 70, 60)",
56683
56907
  "3": "rgb(116, 155, 88)",
56684
- "III": "rgb(116, 155, 88)",
56685
56908
  "4": "rgb(240, 230, 133)",
56686
- "IV": "rgb(240, 230, 133)",
56687
56909
  "5": "rgb(70, 105, 131)",
56688
56910
  "6": "rgb(186, 99, 56)",
56689
56911
  "7": "rgb(93, 177, 221)",
@@ -56731,9 +56953,25 @@
56731
56953
  };
56732
56954
 
56733
56955
  // aliasing
56734
- for (let key of Object.keys(Colors)) {
56956
+ for (let key of Object.keys(GWASColors)) {
56735
56957
  const altName = "chr" + key;
56736
- Colors[altName] = Colors[key];
56958
+ GWASColors[altName] = GWASColors[key];
56959
+ }
56960
+
56961
+ // romanizing
56962
+ for (let a = 1; a <= 48; a++) {
56963
+ if (a === 10) continue; // Don't overide "X"
56964
+ const roman = romanize(a);
56965
+ GWASColors[roman] = GWASColors[a.toString()];
56966
+ }
56967
+ function romanize(num) {
56968
+ if (!+num) return false;
56969
+ var digits = String(+num).split('');
56970
+ var key = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
56971
+ var roman = '',
56972
+ i = 3;
56973
+ while (i--) roman = (key[+digits.pop() + i * 10] || '') + roman;
56974
+ return Array(+digits.join('') + 1).join('M') + roman;
56737
56975
  }
56738
56976
 
56739
56977
  /*
@@ -56781,12 +57019,18 @@
56781
57019
  this.divider = config.divider || "rgb(225,225,225)";
56782
57020
  this.dotSize = config.dotSize || 3;
56783
57021
  this.popoverWindow = config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow;
56784
- this.colorScales = config.color ? new ConstantColorScale(config.color) : {
56785
- "*": new BinnedColorScale(config.colorScale || {
57022
+
57023
+ // Color settings
57024
+ if (this.useChrColors) {
57025
+ this.colorScale = new ColorTable(config.colorTable || GWASColors);
57026
+ } else if (config.color) {
57027
+ this.colorScale = new ConstantColorScale(config.color);
57028
+ } else {
57029
+ this.colorScale = new BinnedColorScale(config.colorScale || {
56786
57030
  thresholds: [5e-8, 5e-4, 0.5],
56787
57031
  colors: ["rgb(255,50,50)", "rgb(251,100,100)", "rgb(251,170,170)", "rgb(227,238,249)"]
56788
- })
56789
- };
57032
+ });
57033
+ }
56790
57034
  this.featureSource = FeatureSource(config, this.browser.genome);
56791
57035
  }
56792
57036
  async postInit() {
@@ -56849,18 +57093,16 @@
56849
57093
  const pos = variant.start;
56850
57094
  if (pos < bpStart) continue;
56851
57095
  if (pos > bpEnd) break;
56852
- const colorScale = this.getColorScale(variant._f ? variant._f.chr : variant.chr);
56853
- let color;
56854
57096
  let val;
56855
57097
  if (this.posteriorProbability) {
56856
57098
  val = variant[this.valueProperty];
56857
- color = colorScale.getColor(val);
56858
57099
  } else {
56859
57100
  const pvalue = variant[this.valueProperty];
56860
57101
  if (!pvalue) continue;
56861
57102
  val = -Math.log10(pvalue);
56862
- color = colorScale.getColor(val);
56863
57103
  }
57104
+ const colorKey = this.useChrColors ? variant._f ? variant._f.chr : variant.chr : val;
57105
+ const color = this.colorScale.getColor(colorKey);
56864
57106
  const yScale = (this.dataRange.max - this.dataRange.min) / pixelHeight;
56865
57107
  const px = Math.round((pos - bpStart) / bpPerPixel);
56866
57108
  const py = Math.max(this.dotSize, pixelHeight - Math.round((val - this.dataRange.min) / yScale));
@@ -56876,19 +57118,6 @@
56876
57118
  }
56877
57119
  }
56878
57120
  }
56879
- getColorScale(chr) {
56880
- if (this.useChrColors) {
56881
- let cs = this.colorScales[chr];
56882
- if (!cs) {
56883
- const color = Colors[chr] || randomColor();
56884
- cs = new ConstantColorScale(color);
56885
- this.colorScales[chr] = cs;
56886
- }
56887
- return cs;
56888
- } else {
56889
- return this.colorScales("*");
56890
- }
56891
- }
56892
57121
  paintAxis(ctx, pixelWidth, pixelHeight) {
56893
57122
  IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {
56894
57123
  'fillStyle': "rgb(255, 255, 255)"
@@ -57001,11 +57230,15 @@
57001
57230
  } else {
57002
57231
  // No features -- pick something reasonable for PPAs and p-values
57003
57232
  if (this.posteriorProbability) {
57004
- this.dataRange.min = this.config.min || 0;
57005
- this.dataRange.max = this.config.max || 1;
57233
+ this.dataRange = {
57234
+ min: this.config.min || 0,
57235
+ max: this.config.max || 1
57236
+ };
57006
57237
  } else {
57007
- this.dataRange.max = this.config.max || 25;
57008
- this.dataRange.min = this.config.min || 0;
57238
+ this.dataRange = {
57239
+ min: this.config.max || 25,
57240
+ max: this.config.min || 0
57241
+ };
57009
57242
  }
57010
57243
  }
57011
57244
  return this.dataRange;