igv 3.0.4 → 3.0.6
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 +13 -11
- package/dist/igv.esm.js +117 -59
- package/dist/igv.esm.min.js +12 -12
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +117 -59
- package/dist/igv.min.js +12 -12
- package/dist/igv.min.js.map +1 -1
- package/package.json +1 -1
package/dist/igv.js
CHANGED
|
@@ -22880,6 +22880,20 @@
|
|
|
22880
22880
|
this.length = dataView.byteLength;
|
|
22881
22881
|
}
|
|
22882
22882
|
|
|
22883
|
+
/**
|
|
22884
|
+
* Print the first "n" bytes to the console. Used for debugging.
|
|
22885
|
+
* @param n
|
|
22886
|
+
*/
|
|
22887
|
+
dumpBytes (n = 100) {
|
|
22888
|
+
const pos = this.position;
|
|
22889
|
+
const bytes = [];
|
|
22890
|
+
for(let i=0; i<= n; i++) {
|
|
22891
|
+
bytes.push(this.getByte());
|
|
22892
|
+
}
|
|
22893
|
+
console.log(bytes.join(" "));
|
|
22894
|
+
this.setPosition(pos);
|
|
22895
|
+
}
|
|
22896
|
+
|
|
22883
22897
|
setPosition(position) {
|
|
22884
22898
|
this.position = position;
|
|
22885
22899
|
}
|
|
@@ -31443,7 +31457,6 @@
|
|
|
31443
31457
|
const idToName = [];
|
|
31444
31458
|
let sumLengths = 0;
|
|
31445
31459
|
const readTreeNode = (offset) => {
|
|
31446
|
-
|
|
31447
31460
|
if (offset >= 0) binaryParser.position = offset;
|
|
31448
31461
|
const type = binaryParser.getByte();
|
|
31449
31462
|
binaryParser.getByte();
|
|
@@ -31480,7 +31493,7 @@
|
|
|
31480
31493
|
};
|
|
31481
31494
|
|
|
31482
31495
|
// Recursively walk tree to populate dictionary
|
|
31483
|
-
readTreeNode(
|
|
31496
|
+
readTreeNode( -1);
|
|
31484
31497
|
|
|
31485
31498
|
return new ChromTree(header, nameToId, idToName, sumLengths)
|
|
31486
31499
|
}
|
|
@@ -32171,6 +32184,16 @@
|
|
|
32171
32184
|
}
|
|
32172
32185
|
}
|
|
32173
32186
|
|
|
32187
|
+
/**
|
|
32188
|
+
* The BB header consists of
|
|
32189
|
+
* (1) the common header
|
|
32190
|
+
* (2) the zoom headers
|
|
32191
|
+
* (3) autosql
|
|
32192
|
+
* (4) total summary block (version 2 and later)
|
|
32193
|
+
*
|
|
32194
|
+
* In addition, we read the chromomsome B+ tree
|
|
32195
|
+
* @returns {Promise<*>}
|
|
32196
|
+
*/
|
|
32174
32197
|
async loadHeader() {
|
|
32175
32198
|
|
|
32176
32199
|
if (this.header) {
|
|
@@ -32188,7 +32211,7 @@
|
|
|
32188
32211
|
// Assume low-to-high unless proven otherwise
|
|
32189
32212
|
this.littleEndian = true;
|
|
32190
32213
|
|
|
32191
|
-
|
|
32214
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32192
32215
|
let magic = binaryParser.getUInt();
|
|
32193
32216
|
if (magic === BIGWIG_MAGIC_LTH$1) {
|
|
32194
32217
|
this.type = "bigwig";
|
|
@@ -32223,30 +32246,33 @@
|
|
|
32223
32246
|
extensionOffset: binaryParser.getLong()
|
|
32224
32247
|
};
|
|
32225
32248
|
|
|
32249
|
+
// Read the next chunk containing zoom headers, autosql, and total summary if present. TotalSummary size = 40 bytes
|
|
32226
32250
|
const startOffset = BBFILE_HEADER_SIZE;
|
|
32251
|
+
const size = header.totalSummaryOffset > 0 ?
|
|
32252
|
+
header.totalSummaryOffset - startOffset + 40 :
|
|
32253
|
+
Math.min(header.fullDataOffset, header.chromTreeOffset) - startOffset;
|
|
32227
32254
|
let range = {
|
|
32228
32255
|
start: startOffset,
|
|
32229
|
-
size:
|
|
32256
|
+
size: size
|
|
32230
32257
|
};
|
|
32231
32258
|
data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {range: range}));
|
|
32232
|
-
|
|
32233
|
-
const nZooms = header.nZoomLevels;
|
|
32234
|
-
binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32259
|
+
const extHeaderParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32235
32260
|
|
|
32236
32261
|
// Load zoom headers, store in order of decreasing reduction level (increasing resolution)
|
|
32262
|
+
const nZooms = header.nZoomLevels;
|
|
32237
32263
|
this.zoomLevelHeaders = [];
|
|
32238
32264
|
this.firstZoomDataOffset = Number.MAX_SAFE_INTEGER;
|
|
32239
32265
|
for (let i = 1; i <= nZooms; i++) {
|
|
32240
32266
|
const zoomNumber = nZooms - i;
|
|
32241
|
-
const zlh = new ZoomLevelHeader(zoomNumber,
|
|
32267
|
+
const zlh = new ZoomLevelHeader(zoomNumber, extHeaderParser);
|
|
32242
32268
|
this.firstZoomDataOffset = Math.min(zlh.dataOffset, this.firstZoomDataOffset);
|
|
32243
32269
|
this.zoomLevelHeaders[zoomNumber] = zlh;
|
|
32244
32270
|
}
|
|
32245
32271
|
|
|
32246
32272
|
// Autosql
|
|
32247
32273
|
if (header.autoSqlOffset > 0) {
|
|
32248
|
-
|
|
32249
|
-
const autoSqlString =
|
|
32274
|
+
extHeaderParser.position = header.autoSqlOffset - startOffset;
|
|
32275
|
+
const autoSqlString = extHeaderParser.getString();
|
|
32250
32276
|
if (autoSqlString) {
|
|
32251
32277
|
this.autoSql = parseAutoSQL(autoSqlString);
|
|
32252
32278
|
}
|
|
@@ -32254,37 +32280,75 @@
|
|
|
32254
32280
|
|
|
32255
32281
|
// Total summary
|
|
32256
32282
|
if (header.totalSummaryOffset > 0) {
|
|
32257
|
-
|
|
32258
|
-
this.totalSummary = new BWTotalSummary(
|
|
32259
|
-
}
|
|
32260
|
-
|
|
32261
|
-
// Chrom data index
|
|
32262
|
-
if (header.chromTreeOffset > 0) {
|
|
32263
|
-
binaryParser.position = header.chromTreeOffset - startOffset;
|
|
32264
|
-
this.chromTree = await ChromTree.parseTree(binaryParser, startOffset, this.genome);
|
|
32265
|
-
this.chrNames = new Set(this.chromTree.idToName);
|
|
32266
|
-
} else {
|
|
32267
|
-
// TODO -- this is an error, not expected
|
|
32268
|
-
throw "BigWig chromosome tree offset <= 0"
|
|
32283
|
+
extHeaderParser.position = header.totalSummaryOffset - startOffset;
|
|
32284
|
+
this.totalSummary = new BWTotalSummary(extHeaderParser);
|
|
32269
32285
|
}
|
|
32270
32286
|
|
|
32271
|
-
//
|
|
32272
|
-
|
|
32273
|
-
|
|
32287
|
+
// Chrom data index. The start is known, size is not, but we can estimate it
|
|
32288
|
+
const bufferSize = Math.min(200000, Math.max(10000, header.fullDataOffset - header.chromTreeOffset));
|
|
32289
|
+
this.chromTree = await this.#readChromTree(header.chromTreeOffset, bufferSize);
|
|
32290
|
+
this.chrNames = new Set(this.chromTree.idToName);
|
|
32274
32291
|
|
|
32275
|
-
|
|
32292
|
+
// Estimate feature density from dataCount (bigbed only)
|
|
32293
|
+
if("bigbed" === this.type) {
|
|
32294
|
+
const dataCount = await this.#readDataCount(header.fullDataOffset);
|
|
32295
|
+
this.featureDensity = dataCount / this.chromTree.sumLengths;
|
|
32296
|
+
}
|
|
32276
32297
|
|
|
32277
32298
|
this.header = header;
|
|
32278
32299
|
|
|
32279
|
-
|
|
32280
32300
|
//extension
|
|
32281
32301
|
if (header.extensionOffset > 0) {
|
|
32282
32302
|
await this.loadExtendedHeader(header.extensionOffset);
|
|
32283
32303
|
}
|
|
32284
|
-
|
|
32304
|
+
return this.header
|
|
32285
32305
|
}
|
|
32286
32306
|
}
|
|
32287
32307
|
|
|
32308
|
+
async #readDataCount(offset) {
|
|
32309
|
+
const data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
32310
|
+
range: {
|
|
32311
|
+
start: offset,
|
|
32312
|
+
size: 4
|
|
32313
|
+
}
|
|
32314
|
+
}));
|
|
32315
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32316
|
+
return binaryParser.getInt()
|
|
32317
|
+
}
|
|
32318
|
+
|
|
32319
|
+
/**
|
|
32320
|
+
* Used when the chromTreeOffset is > fullDataOffset, that is when the chrom tree is not in the initial chunk
|
|
32321
|
+
* read for parsing the header. We know the start position, but not the total size of the chrom tree
|
|
32322
|
+
*
|
|
32323
|
+
* @returns {Promise<void>}
|
|
32324
|
+
*/
|
|
32325
|
+
async #readChromTree(chromTreeOffset, bufferSize) {
|
|
32326
|
+
|
|
32327
|
+
let size = bufferSize;
|
|
32328
|
+
const load = async () => {
|
|
32329
|
+
const data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
32330
|
+
range: {
|
|
32331
|
+
start: chromTreeOffset,
|
|
32332
|
+
size: size
|
|
32333
|
+
}
|
|
32334
|
+
}));
|
|
32335
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32336
|
+
return ChromTree.parseTree(binaryParser, chromTreeOffset, this.genome)
|
|
32337
|
+
};
|
|
32338
|
+
|
|
32339
|
+
let error;
|
|
32340
|
+
while (size < 1000000) {
|
|
32341
|
+
try {
|
|
32342
|
+
const chromTree = await load();
|
|
32343
|
+
return chromTree
|
|
32344
|
+
} catch (e) {
|
|
32345
|
+
error = e;
|
|
32346
|
+
size *= 2;
|
|
32347
|
+
}
|
|
32348
|
+
}
|
|
32349
|
+
throw (error)
|
|
32350
|
+
}
|
|
32351
|
+
|
|
32288
32352
|
async loadExtendedHeader(offset) {
|
|
32289
32353
|
|
|
32290
32354
|
let data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
@@ -33459,7 +33523,10 @@
|
|
|
33459
33523
|
for (let feature of featureList) {
|
|
33460
33524
|
for (let field of searchableFields) {
|
|
33461
33525
|
let key;
|
|
33462
|
-
if
|
|
33526
|
+
if(feature.hasOwnProperty(field)) {
|
|
33527
|
+
key = feature[field];
|
|
33528
|
+
}
|
|
33529
|
+
else if (typeof feature.getAttributeValue === 'function') {
|
|
33463
33530
|
key = feature.getAttributeValue(field);
|
|
33464
33531
|
}
|
|
33465
33532
|
if (key) {
|
|
@@ -39611,6 +39678,10 @@
|
|
|
39611
39678
|
if (this.featureMap[chr]) {
|
|
39612
39679
|
const match = `${chr}-${start}-${end}`;
|
|
39613
39680
|
this.featureMap[chr] = this.featureMap[chr].filter(feature => match !== `${feature.chr}-${feature.start}-${feature.end}`);
|
|
39681
|
+
// Check if featureMap for a specific chromosome is empty now and delete it if yes
|
|
39682
|
+
if (this.featureMap[chr].length === 0) {
|
|
39683
|
+
delete this.featureMap[chr];
|
|
39684
|
+
}
|
|
39614
39685
|
}
|
|
39615
39686
|
}
|
|
39616
39687
|
}
|
|
@@ -43058,7 +43129,7 @@
|
|
|
43058
43129
|
const viewportsToRepaint = visibleViewports.filter(vp => vp.needsRepaint()).filter(viewport => viewport.checkZoomIn());
|
|
43059
43130
|
|
|
43060
43131
|
// Get viewports that require a data load
|
|
43061
|
-
const viewportsToReload = visibleViewports.filter(viewport => viewport.needsReload());
|
|
43132
|
+
const viewportsToReload = visibleViewports.filter(viewport => viewport.checkZoomIn()).filter(viewport => viewport.needsReload());
|
|
43062
43133
|
|
|
43063
43134
|
// Trigger viewport to load features needed to cover current genomic range
|
|
43064
43135
|
// NOTE: these must be loaded synchronously, do not user Promise.all, not all file readers are thread safe
|
|
@@ -70523,7 +70594,7 @@
|
|
|
70523
70594
|
})
|
|
70524
70595
|
}
|
|
70525
70596
|
|
|
70526
|
-
const _version = "3.0.
|
|
70597
|
+
const _version = "3.0.6";
|
|
70527
70598
|
function version() {
|
|
70528
70599
|
return _version
|
|
70529
70600
|
}
|
|
@@ -72073,9 +72144,16 @@
|
|
|
72073
72144
|
'<hr/>',
|
|
72074
72145
|
{
|
|
72075
72146
|
label: 'Delete',
|
|
72076
|
-
click: () => {
|
|
72077
|
-
|
|
72078
|
-
|
|
72147
|
+
click: async () => {
|
|
72148
|
+
roiSet.removeFeature(feature);
|
|
72149
|
+
const userDefinedFeatures = await roiSet.getAllFeatures();
|
|
72150
|
+
|
|
72151
|
+
// Delete user defined ROI Set if it is empty
|
|
72152
|
+
if (Object.keys(userDefinedFeatures).length === 0) {
|
|
72153
|
+
roiManager.deleteUserDefinedROISet();
|
|
72154
|
+
}
|
|
72155
|
+
roiManager.deleteRegionWithKey(regionElement.dataset.region, columnContainer);
|
|
72156
|
+
roiManager.repaintTable();
|
|
72079
72157
|
}
|
|
72080
72158
|
}
|
|
72081
72159
|
);
|
|
@@ -72603,6 +72681,10 @@
|
|
|
72603
72681
|
return this.roiSets.find(roiSet => true === roiSet.isUserDefined)
|
|
72604
72682
|
}
|
|
72605
72683
|
|
|
72684
|
+
deleteUserDefinedROISet(){
|
|
72685
|
+
this.roiSets = this.roiSets.filter(roiSet => roiSet.isUserDefined !== true);
|
|
72686
|
+
}
|
|
72687
|
+
|
|
72606
72688
|
initializeUserDefinedROISet() {
|
|
72607
72689
|
|
|
72608
72690
|
const config =
|
|
@@ -72618,15 +72700,8 @@
|
|
|
72618
72700
|
}
|
|
72619
72701
|
|
|
72620
72702
|
async deleteRegionWithKey(regionKey, columnContainer) {
|
|
72621
|
-
|
|
72622
72703
|
columnContainer.querySelectorAll(createSelector(regionKey)).forEach(node => node.remove());
|
|
72623
72704
|
|
|
72624
|
-
const {feature, set} = await this.findRegionWithKey(regionKey);
|
|
72625
|
-
|
|
72626
|
-
if (set) {
|
|
72627
|
-
set.removeFeature(feature);
|
|
72628
|
-
}
|
|
72629
|
-
|
|
72630
72705
|
const records = await this.getTableRecords();
|
|
72631
72706
|
|
|
72632
72707
|
if (0 === records.length) {
|
|
@@ -72636,23 +72711,6 @@
|
|
|
72636
72711
|
|
|
72637
72712
|
}
|
|
72638
72713
|
|
|
72639
|
-
async findRegionWithKey(regionKey) {
|
|
72640
|
-
|
|
72641
|
-
const {chr, start, end} = parseRegionKey(regionKey);
|
|
72642
|
-
|
|
72643
|
-
for (let set of this.roiSets) {
|
|
72644
|
-
const features = await set.getFeatures(chr, start, end);
|
|
72645
|
-
|
|
72646
|
-
for (let feature of features) {
|
|
72647
|
-
if (feature.chr === chr && feature.start >= start && feature.end <= end) {
|
|
72648
|
-
return {feature, set}
|
|
72649
|
-
}
|
|
72650
|
-
}
|
|
72651
|
-
}
|
|
72652
|
-
|
|
72653
|
-
return {feature: undefined, set: undefined}
|
|
72654
|
-
}
|
|
72655
|
-
|
|
72656
72714
|
toJSON() {
|
|
72657
72715
|
return this.roiSets.map(roiSet => roiSet.toJSON())
|
|
72658
72716
|
}
|
|
@@ -76271,7 +76329,7 @@
|
|
|
76271
76329
|
async function keyUpHandler(event) {
|
|
76272
76330
|
|
|
76273
76331
|
// Feature jumping disabled in multi-locus view
|
|
76274
|
-
if (this.referenceFrameList.length > 1) return
|
|
76332
|
+
if (!this.referenceFrameList || this.referenceFrameList.length > 1) return
|
|
76275
76333
|
|
|
76276
76334
|
if (event.code === 'KeyF' || event.code === 'KeyB') {
|
|
76277
76335
|
|