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/README.md
CHANGED
|
@@ -18,19 +18,19 @@ Below are examples and a quickstart guide. See the [developer documentation](ht
|
|
|
18
18
|
|
|
19
19
|
# Examples
|
|
20
20
|
|
|
21
|
-
***[Alignments](https://igv.org/web/release/3.0.
|
|
21
|
+
***[Alignments](https://igv.org/web/release/3.0.6/examples/cram-vcf.html)***
|
|
22
22
|
|
|
23
|
-
***[Interactions](https://igv.org/web/release/3.0.
|
|
23
|
+
***[Interactions](https://igv.org/web/release/3.0.6/examples/interact.html)***
|
|
24
24
|
|
|
25
|
-
***[Copy number](https://igv.org/web/release/3.0.
|
|
25
|
+
***[Copy number](https://igv.org/web/release/3.0.6/examples/copyNumber.html)***
|
|
26
26
|
|
|
27
|
-
***[Multiple regions](https://igv.org/web/release/3.0.
|
|
27
|
+
***[Multiple regions](https://igv.org/web/release/3.0.6/examples/multi-locus.html)***
|
|
28
28
|
|
|
29
|
-
***[Mutation Annotation Format (MAF)](https://igv.org/web/release/3.0.
|
|
29
|
+
***[Mutation Annotation Format (MAF)](https://igv.org/web/release/3.0.6/examples/maf-tcga.html)***
|
|
30
30
|
|
|
31
|
-
***[Variant color options](https://igv.org/web/release/3.0.
|
|
31
|
+
***[Variant color options](https://igv.org/web/release/3.0.6/examples/variant-colors.html)***
|
|
32
32
|
|
|
33
|
-
***[More](https://igv.org/web/release/3.0.
|
|
33
|
+
***[More](https://igv.org/web/release/3.0.6/examples/)***
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
# Quickstart
|
|
@@ -39,18 +39,18 @@ Below are examples and a quickstart guide. See the [developer documentation](ht
|
|
|
39
39
|
igv.js consists of a single javascript file with no external dependencies.
|
|
40
40
|
|
|
41
41
|
Pre-built files for script include, AMD, or CJS module systems (igv.min.js) and an ES6 module (igv.esm.min.js)
|
|
42
|
-
can be downloaded from [https://cdn.jsdelivr.net/npm/igv@3.0.
|
|
42
|
+
can be downloaded from [https://cdn.jsdelivr.net/npm/igv@3.0.6/dist/](https://cdn.jsdelivr.net/npm/igv@3.0.6/dist/).
|
|
43
43
|
|
|
44
44
|
To import igv as an ES6 module
|
|
45
45
|
|
|
46
46
|
```javascript
|
|
47
|
-
import igv from "https://cdn.jsdelivr.net/npm/igv@3.0.
|
|
47
|
+
import igv from "https://cdn.jsdelivr.net/npm/igv@3.0.6/dist/igv.esm.min.js"
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Or as a script include (defines the "igv" global)
|
|
51
51
|
|
|
52
52
|
```html
|
|
53
|
-
<script src="https://cdn.jsdelivr.net/npm/igv@3.0.
|
|
53
|
+
<script src="https://cdn.jsdelivr.net/npm/igv@3.0.6/dist/igv.min.js"></script>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Alternatively you can install with npm
|
|
@@ -91,7 +91,9 @@ a browser on a single alignment track opened at a specific locus:
|
|
|
91
91
|
})
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
## Documentation
|
|
95
|
+
|
|
96
|
+
Full documentation of the igv.js API is available at [https://igv.org/doc/igvjs/](https://igv.org/doc/igvjs/).
|
|
95
97
|
|
|
96
98
|
## Development
|
|
97
99
|
|
package/dist/igv.esm.js
CHANGED
|
@@ -22874,6 +22874,20 @@ class BinaryParser$1 {
|
|
|
22874
22874
|
this.length = dataView.byteLength;
|
|
22875
22875
|
}
|
|
22876
22876
|
|
|
22877
|
+
/**
|
|
22878
|
+
* Print the first "n" bytes to the console. Used for debugging.
|
|
22879
|
+
* @param n
|
|
22880
|
+
*/
|
|
22881
|
+
dumpBytes (n = 100) {
|
|
22882
|
+
const pos = this.position;
|
|
22883
|
+
const bytes = [];
|
|
22884
|
+
for(let i=0; i<= n; i++) {
|
|
22885
|
+
bytes.push(this.getByte());
|
|
22886
|
+
}
|
|
22887
|
+
console.log(bytes.join(" "));
|
|
22888
|
+
this.setPosition(pos);
|
|
22889
|
+
}
|
|
22890
|
+
|
|
22877
22891
|
setPosition(position) {
|
|
22878
22892
|
this.position = position;
|
|
22879
22893
|
}
|
|
@@ -31437,7 +31451,6 @@ class ChromTree {
|
|
|
31437
31451
|
const idToName = [];
|
|
31438
31452
|
let sumLengths = 0;
|
|
31439
31453
|
const readTreeNode = (offset) => {
|
|
31440
|
-
|
|
31441
31454
|
if (offset >= 0) binaryParser.position = offset;
|
|
31442
31455
|
const type = binaryParser.getByte();
|
|
31443
31456
|
binaryParser.getByte();
|
|
@@ -31474,7 +31487,7 @@ class ChromTree {
|
|
|
31474
31487
|
};
|
|
31475
31488
|
|
|
31476
31489
|
// Recursively walk tree to populate dictionary
|
|
31477
|
-
readTreeNode(
|
|
31490
|
+
readTreeNode( -1);
|
|
31478
31491
|
|
|
31479
31492
|
return new ChromTree(header, nameToId, idToName, sumLengths)
|
|
31480
31493
|
}
|
|
@@ -32165,6 +32178,16 @@ class BWReader {
|
|
|
32165
32178
|
}
|
|
32166
32179
|
}
|
|
32167
32180
|
|
|
32181
|
+
/**
|
|
32182
|
+
* The BB header consists of
|
|
32183
|
+
* (1) the common header
|
|
32184
|
+
* (2) the zoom headers
|
|
32185
|
+
* (3) autosql
|
|
32186
|
+
* (4) total summary block (version 2 and later)
|
|
32187
|
+
*
|
|
32188
|
+
* In addition, we read the chromomsome B+ tree
|
|
32189
|
+
* @returns {Promise<*>}
|
|
32190
|
+
*/
|
|
32168
32191
|
async loadHeader() {
|
|
32169
32192
|
|
|
32170
32193
|
if (this.header) {
|
|
@@ -32182,7 +32205,7 @@ class BWReader {
|
|
|
32182
32205
|
// Assume low-to-high unless proven otherwise
|
|
32183
32206
|
this.littleEndian = true;
|
|
32184
32207
|
|
|
32185
|
-
|
|
32208
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32186
32209
|
let magic = binaryParser.getUInt();
|
|
32187
32210
|
if (magic === BIGWIG_MAGIC_LTH$1) {
|
|
32188
32211
|
this.type = "bigwig";
|
|
@@ -32217,30 +32240,33 @@ class BWReader {
|
|
|
32217
32240
|
extensionOffset: binaryParser.getLong()
|
|
32218
32241
|
};
|
|
32219
32242
|
|
|
32243
|
+
// Read the next chunk containing zoom headers, autosql, and total summary if present. TotalSummary size = 40 bytes
|
|
32220
32244
|
const startOffset = BBFILE_HEADER_SIZE;
|
|
32245
|
+
const size = header.totalSummaryOffset > 0 ?
|
|
32246
|
+
header.totalSummaryOffset - startOffset + 40 :
|
|
32247
|
+
Math.min(header.fullDataOffset, header.chromTreeOffset) - startOffset;
|
|
32221
32248
|
let range = {
|
|
32222
32249
|
start: startOffset,
|
|
32223
|
-
size:
|
|
32250
|
+
size: size
|
|
32224
32251
|
};
|
|
32225
32252
|
data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {range: range}));
|
|
32226
|
-
|
|
32227
|
-
const nZooms = header.nZoomLevels;
|
|
32228
|
-
binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32253
|
+
const extHeaderParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32229
32254
|
|
|
32230
32255
|
// Load zoom headers, store in order of decreasing reduction level (increasing resolution)
|
|
32256
|
+
const nZooms = header.nZoomLevels;
|
|
32231
32257
|
this.zoomLevelHeaders = [];
|
|
32232
32258
|
this.firstZoomDataOffset = Number.MAX_SAFE_INTEGER;
|
|
32233
32259
|
for (let i = 1; i <= nZooms; i++) {
|
|
32234
32260
|
const zoomNumber = nZooms - i;
|
|
32235
|
-
const zlh = new ZoomLevelHeader(zoomNumber,
|
|
32261
|
+
const zlh = new ZoomLevelHeader(zoomNumber, extHeaderParser);
|
|
32236
32262
|
this.firstZoomDataOffset = Math.min(zlh.dataOffset, this.firstZoomDataOffset);
|
|
32237
32263
|
this.zoomLevelHeaders[zoomNumber] = zlh;
|
|
32238
32264
|
}
|
|
32239
32265
|
|
|
32240
32266
|
// Autosql
|
|
32241
32267
|
if (header.autoSqlOffset > 0) {
|
|
32242
|
-
|
|
32243
|
-
const autoSqlString =
|
|
32268
|
+
extHeaderParser.position = header.autoSqlOffset - startOffset;
|
|
32269
|
+
const autoSqlString = extHeaderParser.getString();
|
|
32244
32270
|
if (autoSqlString) {
|
|
32245
32271
|
this.autoSql = parseAutoSQL(autoSqlString);
|
|
32246
32272
|
}
|
|
@@ -32248,37 +32274,75 @@ class BWReader {
|
|
|
32248
32274
|
|
|
32249
32275
|
// Total summary
|
|
32250
32276
|
if (header.totalSummaryOffset > 0) {
|
|
32251
|
-
|
|
32252
|
-
this.totalSummary = new BWTotalSummary(
|
|
32253
|
-
}
|
|
32254
|
-
|
|
32255
|
-
// Chrom data index
|
|
32256
|
-
if (header.chromTreeOffset > 0) {
|
|
32257
|
-
binaryParser.position = header.chromTreeOffset - startOffset;
|
|
32258
|
-
this.chromTree = await ChromTree.parseTree(binaryParser, startOffset, this.genome);
|
|
32259
|
-
this.chrNames = new Set(this.chromTree.idToName);
|
|
32260
|
-
} else {
|
|
32261
|
-
// TODO -- this is an error, not expected
|
|
32262
|
-
throw "BigWig chromosome tree offset <= 0"
|
|
32277
|
+
extHeaderParser.position = header.totalSummaryOffset - startOffset;
|
|
32278
|
+
this.totalSummary = new BWTotalSummary(extHeaderParser);
|
|
32263
32279
|
}
|
|
32264
32280
|
|
|
32265
|
-
//
|
|
32266
|
-
|
|
32267
|
-
|
|
32281
|
+
// Chrom data index. The start is known, size is not, but we can estimate it
|
|
32282
|
+
const bufferSize = Math.min(200000, Math.max(10000, header.fullDataOffset - header.chromTreeOffset));
|
|
32283
|
+
this.chromTree = await this.#readChromTree(header.chromTreeOffset, bufferSize);
|
|
32284
|
+
this.chrNames = new Set(this.chromTree.idToName);
|
|
32268
32285
|
|
|
32269
|
-
|
|
32286
|
+
// Estimate feature density from dataCount (bigbed only)
|
|
32287
|
+
if("bigbed" === this.type) {
|
|
32288
|
+
const dataCount = await this.#readDataCount(header.fullDataOffset);
|
|
32289
|
+
this.featureDensity = dataCount / this.chromTree.sumLengths;
|
|
32290
|
+
}
|
|
32270
32291
|
|
|
32271
32292
|
this.header = header;
|
|
32272
32293
|
|
|
32273
|
-
|
|
32274
32294
|
//extension
|
|
32275
32295
|
if (header.extensionOffset > 0) {
|
|
32276
32296
|
await this.loadExtendedHeader(header.extensionOffset);
|
|
32277
32297
|
}
|
|
32278
|
-
|
|
32298
|
+
return this.header
|
|
32279
32299
|
}
|
|
32280
32300
|
}
|
|
32281
32301
|
|
|
32302
|
+
async #readDataCount(offset) {
|
|
32303
|
+
const data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
32304
|
+
range: {
|
|
32305
|
+
start: offset,
|
|
32306
|
+
size: 4
|
|
32307
|
+
}
|
|
32308
|
+
}));
|
|
32309
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32310
|
+
return binaryParser.getInt()
|
|
32311
|
+
}
|
|
32312
|
+
|
|
32313
|
+
/**
|
|
32314
|
+
* Used when the chromTreeOffset is > fullDataOffset, that is when the chrom tree is not in the initial chunk
|
|
32315
|
+
* read for parsing the header. We know the start position, but not the total size of the chrom tree
|
|
32316
|
+
*
|
|
32317
|
+
* @returns {Promise<void>}
|
|
32318
|
+
*/
|
|
32319
|
+
async #readChromTree(chromTreeOffset, bufferSize) {
|
|
32320
|
+
|
|
32321
|
+
let size = bufferSize;
|
|
32322
|
+
const load = async () => {
|
|
32323
|
+
const data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
32324
|
+
range: {
|
|
32325
|
+
start: chromTreeOffset,
|
|
32326
|
+
size: size
|
|
32327
|
+
}
|
|
32328
|
+
}));
|
|
32329
|
+
const binaryParser = new BinaryParser$1(new DataView(data), this.littleEndian);
|
|
32330
|
+
return ChromTree.parseTree(binaryParser, chromTreeOffset, this.genome)
|
|
32331
|
+
};
|
|
32332
|
+
|
|
32333
|
+
let error;
|
|
32334
|
+
while (size < 1000000) {
|
|
32335
|
+
try {
|
|
32336
|
+
const chromTree = await load();
|
|
32337
|
+
return chromTree
|
|
32338
|
+
} catch (e) {
|
|
32339
|
+
error = e;
|
|
32340
|
+
size *= 2;
|
|
32341
|
+
}
|
|
32342
|
+
}
|
|
32343
|
+
throw (error)
|
|
32344
|
+
}
|
|
32345
|
+
|
|
32282
32346
|
async loadExtendedHeader(offset) {
|
|
32283
32347
|
|
|
32284
32348
|
let data = await this.loader.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
@@ -33453,7 +33517,10 @@ class TextFeatureSource extends BaseFeatureSource {
|
|
|
33453
33517
|
for (let feature of featureList) {
|
|
33454
33518
|
for (let field of searchableFields) {
|
|
33455
33519
|
let key;
|
|
33456
|
-
if
|
|
33520
|
+
if(feature.hasOwnProperty(field)) {
|
|
33521
|
+
key = feature[field];
|
|
33522
|
+
}
|
|
33523
|
+
else if (typeof feature.getAttributeValue === 'function') {
|
|
33457
33524
|
key = feature.getAttributeValue(field);
|
|
33458
33525
|
}
|
|
33459
33526
|
if (key) {
|
|
@@ -39605,6 +39672,10 @@ class DynamicFeatureSource {
|
|
|
39605
39672
|
if (this.featureMap[chr]) {
|
|
39606
39673
|
const match = `${chr}-${start}-${end}`;
|
|
39607
39674
|
this.featureMap[chr] = this.featureMap[chr].filter(feature => match !== `${feature.chr}-${feature.start}-${feature.end}`);
|
|
39675
|
+
// Check if featureMap for a specific chromosome is empty now and delete it if yes
|
|
39676
|
+
if (this.featureMap[chr].length === 0) {
|
|
39677
|
+
delete this.featureMap[chr];
|
|
39678
|
+
}
|
|
39608
39679
|
}
|
|
39609
39680
|
}
|
|
39610
39681
|
}
|
|
@@ -43052,7 +43123,7 @@ class TrackView {
|
|
|
43052
43123
|
const viewportsToRepaint = visibleViewports.filter(vp => vp.needsRepaint()).filter(viewport => viewport.checkZoomIn());
|
|
43053
43124
|
|
|
43054
43125
|
// Get viewports that require a data load
|
|
43055
|
-
const viewportsToReload = visibleViewports.filter(viewport => viewport.needsReload());
|
|
43126
|
+
const viewportsToReload = visibleViewports.filter(viewport => viewport.checkZoomIn()).filter(viewport => viewport.needsReload());
|
|
43056
43127
|
|
|
43057
43128
|
// Trigger viewport to load features needed to cover current genomic range
|
|
43058
43129
|
// NOTE: these must be loaded synchronously, do not user Promise.all, not all file readers are thread safe
|
|
@@ -70517,7 +70588,7 @@ function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, v
|
|
|
70517
70588
|
})
|
|
70518
70589
|
}
|
|
70519
70590
|
|
|
70520
|
-
const _version = "3.0.
|
|
70591
|
+
const _version = "3.0.6";
|
|
70521
70592
|
function version() {
|
|
70522
70593
|
return _version
|
|
70523
70594
|
}
|
|
@@ -72067,9 +72138,16 @@ class ROIMenu {
|
|
|
72067
72138
|
'<hr/>',
|
|
72068
72139
|
{
|
|
72069
72140
|
label: 'Delete',
|
|
72070
|
-
click: () => {
|
|
72071
|
-
|
|
72072
|
-
|
|
72141
|
+
click: async () => {
|
|
72142
|
+
roiSet.removeFeature(feature);
|
|
72143
|
+
const userDefinedFeatures = await roiSet.getAllFeatures();
|
|
72144
|
+
|
|
72145
|
+
// Delete user defined ROI Set if it is empty
|
|
72146
|
+
if (Object.keys(userDefinedFeatures).length === 0) {
|
|
72147
|
+
roiManager.deleteUserDefinedROISet();
|
|
72148
|
+
}
|
|
72149
|
+
roiManager.deleteRegionWithKey(regionElement.dataset.region, columnContainer);
|
|
72150
|
+
roiManager.repaintTable();
|
|
72073
72151
|
}
|
|
72074
72152
|
}
|
|
72075
72153
|
);
|
|
@@ -72597,6 +72675,10 @@ class ROIManager {
|
|
|
72597
72675
|
return this.roiSets.find(roiSet => true === roiSet.isUserDefined)
|
|
72598
72676
|
}
|
|
72599
72677
|
|
|
72678
|
+
deleteUserDefinedROISet(){
|
|
72679
|
+
this.roiSets = this.roiSets.filter(roiSet => roiSet.isUserDefined !== true);
|
|
72680
|
+
}
|
|
72681
|
+
|
|
72600
72682
|
initializeUserDefinedROISet() {
|
|
72601
72683
|
|
|
72602
72684
|
const config =
|
|
@@ -72612,15 +72694,8 @@ class ROIManager {
|
|
|
72612
72694
|
}
|
|
72613
72695
|
|
|
72614
72696
|
async deleteRegionWithKey(regionKey, columnContainer) {
|
|
72615
|
-
|
|
72616
72697
|
columnContainer.querySelectorAll(createSelector(regionKey)).forEach(node => node.remove());
|
|
72617
72698
|
|
|
72618
|
-
const {feature, set} = await this.findRegionWithKey(regionKey);
|
|
72619
|
-
|
|
72620
|
-
if (set) {
|
|
72621
|
-
set.removeFeature(feature);
|
|
72622
|
-
}
|
|
72623
|
-
|
|
72624
72699
|
const records = await this.getTableRecords();
|
|
72625
72700
|
|
|
72626
72701
|
if (0 === records.length) {
|
|
@@ -72630,23 +72705,6 @@ class ROIManager {
|
|
|
72630
72705
|
|
|
72631
72706
|
}
|
|
72632
72707
|
|
|
72633
|
-
async findRegionWithKey(regionKey) {
|
|
72634
|
-
|
|
72635
|
-
const {chr, start, end} = parseRegionKey(regionKey);
|
|
72636
|
-
|
|
72637
|
-
for (let set of this.roiSets) {
|
|
72638
|
-
const features = await set.getFeatures(chr, start, end);
|
|
72639
|
-
|
|
72640
|
-
for (let feature of features) {
|
|
72641
|
-
if (feature.chr === chr && feature.start >= start && feature.end <= end) {
|
|
72642
|
-
return {feature, set}
|
|
72643
|
-
}
|
|
72644
|
-
}
|
|
72645
|
-
}
|
|
72646
|
-
|
|
72647
|
-
return {feature: undefined, set: undefined}
|
|
72648
|
-
}
|
|
72649
|
-
|
|
72650
72708
|
toJSON() {
|
|
72651
72709
|
return this.roiSets.map(roiSet => roiSet.toJSON())
|
|
72652
72710
|
}
|
|
@@ -76265,7 +76323,7 @@ function mouseUpOrLeave(e) {
|
|
|
76265
76323
|
async function keyUpHandler(event) {
|
|
76266
76324
|
|
|
76267
76325
|
// Feature jumping disabled in multi-locus view
|
|
76268
|
-
if (this.referenceFrameList.length > 1) return
|
|
76326
|
+
if (!this.referenceFrameList || this.referenceFrameList.length > 1) return
|
|
76269
76327
|
|
|
76270
76328
|
if (event.code === 'KeyF' || event.code === 'KeyB') {
|
|
76271
76329
|
|