igv 3.3.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/igv.d.ts +665 -0
- package/dist/igv.esm.js +510 -178
- package/dist/igv.esm.min.js +9 -9
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +510 -178
- package/dist/igv.min.js +9 -9
- package/dist/igv.min.js.map +1 -1
- package/package.json +5 -3
package/dist/igv.js
CHANGED
|
@@ -379,7 +379,7 @@
|
|
|
379
379
|
* @param x
|
|
380
380
|
* @returns {boolean}
|
|
381
381
|
*/
|
|
382
|
-
function isString$
|
|
382
|
+
function isString$3(x) {
|
|
383
383
|
return typeof x === "string" || x instanceof String
|
|
384
384
|
}
|
|
385
385
|
|
|
@@ -479,7 +479,7 @@
|
|
|
479
479
|
|
|
480
480
|
if (urlOrFile.name !== undefined) {
|
|
481
481
|
return urlOrFile.name
|
|
482
|
-
} else if (isString$
|
|
482
|
+
} else if (isString$3(urlOrFile)) {
|
|
483
483
|
|
|
484
484
|
let index = urlOrFile.lastIndexOf("/");
|
|
485
485
|
let filename = index < 0 ? urlOrFile : urlOrFile.substr(index + 1);
|
|
@@ -10684,7 +10684,7 @@
|
|
|
10684
10684
|
};
|
|
10685
10685
|
|
|
10686
10686
|
async function getFilename$1(url) {
|
|
10687
|
-
if (isString$
|
|
10687
|
+
if (isString$3(url) && url.startsWith("https://drive.google.com")) {
|
|
10688
10688
|
// This will fail if Google API key is not defined
|
|
10689
10689
|
if (getApiKey() === undefined) {
|
|
10690
10690
|
throw Error("Google drive is referenced, but API key is not defined. An API key is required for Google Drive access")
|
|
@@ -10726,7 +10726,7 @@
|
|
|
10726
10726
|
|
|
10727
10727
|
|
|
10728
10728
|
function isDataURL(obj) {
|
|
10729
|
-
return (isString$
|
|
10729
|
+
return (isString$3(obj) && obj.startsWith("data:"))
|
|
10730
10730
|
}
|
|
10731
10731
|
|
|
10732
10732
|
function createColumn(columnContainer, className) {
|
|
@@ -10952,7 +10952,7 @@
|
|
|
10952
10952
|
return list;
|
|
10953
10953
|
}
|
|
10954
10954
|
|
|
10955
|
-
/*! @license DOMPurify 3.2.
|
|
10955
|
+
/*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */
|
|
10956
10956
|
|
|
10957
10957
|
const {
|
|
10958
10958
|
entries,
|
|
@@ -11156,7 +11156,7 @@
|
|
|
11156
11156
|
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
11157
11157
|
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
11158
11158
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
11159
|
-
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
11159
|
+
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
11160
11160
|
);
|
|
11161
11161
|
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
11162
11162
|
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
@@ -11253,7 +11253,7 @@
|
|
|
11253
11253
|
function createDOMPurify() {
|
|
11254
11254
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
11255
11255
|
const DOMPurify = root => createDOMPurify(root);
|
|
11256
|
-
DOMPurify.version = '3.2.
|
|
11256
|
+
DOMPurify.version = '3.2.6';
|
|
11257
11257
|
DOMPurify.removed = [];
|
|
11258
11258
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
11259
11259
|
// Not running in a browser, provide a factory function
|
|
@@ -11492,8 +11492,8 @@
|
|
|
11492
11492
|
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
11493
11493
|
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
11494
11494
|
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
11495
|
-
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
|
11496
|
-
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
11495
|
+
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
|
|
11496
|
+
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
|
|
11497
11497
|
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
|
11498
11498
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
11499
11499
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
@@ -11858,7 +11858,7 @@
|
|
|
11858
11858
|
allowedTags: ALLOWED_TAGS
|
|
11859
11859
|
});
|
|
11860
11860
|
/* Detect mXSS attempts abusing namespace confusion */
|
|
11861
|
-
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
|
|
11861
|
+
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
|
|
11862
11862
|
_forceRemove(currentNode);
|
|
11863
11863
|
return true;
|
|
11864
11864
|
}
|
|
@@ -12010,7 +12010,8 @@
|
|
|
12010
12010
|
value: attrValue
|
|
12011
12011
|
} = attr;
|
|
12012
12012
|
const lcName = transformCaseFunc(name);
|
|
12013
|
-
|
|
12013
|
+
const initValue = attrValue;
|
|
12014
|
+
let value = name === 'value' ? initValue : stringTrim(initValue);
|
|
12014
12015
|
/* Execute a hook if present */
|
|
12015
12016
|
hookEvent.attrName = lcName;
|
|
12016
12017
|
hookEvent.attrValue = value;
|
|
@@ -12036,10 +12037,9 @@
|
|
|
12036
12037
|
if (hookEvent.forceKeepAttr) {
|
|
12037
12038
|
continue;
|
|
12038
12039
|
}
|
|
12039
|
-
/* Remove attribute */
|
|
12040
|
-
_removeAttribute(name, currentNode);
|
|
12041
12040
|
/* Did the hooks approve of the attribute? */
|
|
12042
12041
|
if (!hookEvent.keepAttr) {
|
|
12042
|
+
_removeAttribute(name, currentNode);
|
|
12043
12043
|
continue;
|
|
12044
12044
|
}
|
|
12045
12045
|
/* Work around a security issue in jQuery 3.0 */
|
|
@@ -12056,6 +12056,7 @@
|
|
|
12056
12056
|
/* Is `value` valid for this attribute? */
|
|
12057
12057
|
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
12058
12058
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
12059
|
+
_removeAttribute(name, currentNode);
|
|
12059
12060
|
continue;
|
|
12060
12061
|
}
|
|
12061
12062
|
/* Handle attributes that require Trusted Types */
|
|
@@ -12076,19 +12077,23 @@
|
|
|
12076
12077
|
}
|
|
12077
12078
|
}
|
|
12078
12079
|
/* Handle invalid data-* attribute set by try-catching it */
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12080
|
+
if (value !== initValue) {
|
|
12081
|
+
try {
|
|
12082
|
+
if (namespaceURI) {
|
|
12083
|
+
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
12084
|
+
} else {
|
|
12085
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
12086
|
+
currentNode.setAttribute(name, value);
|
|
12087
|
+
}
|
|
12088
|
+
if (_isClobbered(currentNode)) {
|
|
12089
|
+
_forceRemove(currentNode);
|
|
12090
|
+
} else {
|
|
12091
|
+
arrayPop(DOMPurify.removed);
|
|
12092
|
+
}
|
|
12093
|
+
} catch (_) {
|
|
12094
|
+
_removeAttribute(name, currentNode);
|
|
12090
12095
|
}
|
|
12091
|
-
}
|
|
12096
|
+
}
|
|
12092
12097
|
}
|
|
12093
12098
|
/* Execute a hook if present */
|
|
12094
12099
|
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
|
|
@@ -16909,7 +16914,7 @@
|
|
|
16909
16914
|
*/
|
|
16910
16915
|
|
|
16911
16916
|
const fixColor = (colorString) => {
|
|
16912
|
-
if (isString$
|
|
16917
|
+
if (isString$3(colorString)) {
|
|
16913
16918
|
return (colorString.indexOf(",") > 0 && !(colorString.startsWith("rgb(") || colorString.startsWith("rgba("))) ?
|
|
16914
16919
|
`rgb(${colorString})` : colorString
|
|
16915
16920
|
} else {
|
|
@@ -16981,7 +16986,7 @@
|
|
|
16981
16986
|
this.name = config.name || config.label;
|
|
16982
16987
|
} else if (isFile(config.url)) {
|
|
16983
16988
|
this.name = config.url.name;
|
|
16984
|
-
} else if (isString$
|
|
16989
|
+
} else if (isString$3(config.url) && !config.url.startsWith("data:")) {
|
|
16985
16990
|
this.name = getFilename$2(config.url);
|
|
16986
16991
|
}
|
|
16987
16992
|
|
|
@@ -20903,7 +20908,7 @@
|
|
|
20903
20908
|
* THE SOFTWARE.
|
|
20904
20909
|
*/
|
|
20905
20910
|
|
|
20906
|
-
const isString$
|
|
20911
|
+
const isString$2 = isString$3;
|
|
20907
20912
|
|
|
20908
20913
|
|
|
20909
20914
|
class CustomServiceReader {
|
|
@@ -20942,7 +20947,7 @@
|
|
|
20942
20947
|
if (data) {
|
|
20943
20948
|
if (typeof this.config.parser === "function") {
|
|
20944
20949
|
features = this.config.parser(data);
|
|
20945
|
-
} else if (isString$
|
|
20950
|
+
} else if (isString$2(data)) {
|
|
20946
20951
|
features = JSON.parse(data);
|
|
20947
20952
|
} else {
|
|
20948
20953
|
features = data;
|
|
@@ -22343,7 +22348,7 @@
|
|
|
22343
22348
|
}
|
|
22344
22349
|
|
|
22345
22350
|
function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
22346
|
-
|
|
22351
|
+
//biggenepred
|
|
22347
22352
|
if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table || 'interact' === autoSql.table))) {
|
|
22348
22353
|
return decodeInteract
|
|
22349
22354
|
} else {
|
|
@@ -22390,9 +22395,20 @@
|
|
|
22390
22395
|
const extraStart = definedFieldCount;
|
|
22391
22396
|
for (let i = extraStart; i < fieldCount; i++) {
|
|
22392
22397
|
if (i < autoSql.fields.length) {
|
|
22398
|
+
|
|
22393
22399
|
const name = autoSql.fields[i].name;
|
|
22394
|
-
|
|
22395
|
-
|
|
22400
|
+
|
|
22401
|
+
if (name === "exonFrames") {
|
|
22402
|
+
const frameOffsets = tokens[i - 3].replace(/,$/, '').split(',');
|
|
22403
|
+
for (let i = 0; i < feature.exons.length; i++) {
|
|
22404
|
+
const exon = feature.exons[i];
|
|
22405
|
+
const fo = parseInt(frameOffsets[i]);
|
|
22406
|
+
if (fo != -1) exon.readingFrame = fo;
|
|
22407
|
+
}
|
|
22408
|
+
} else {
|
|
22409
|
+
const value = tokens[i - 3];
|
|
22410
|
+
feature[name] = value;
|
|
22411
|
+
}
|
|
22396
22412
|
}
|
|
22397
22413
|
}
|
|
22398
22414
|
}
|
|
@@ -22438,6 +22454,7 @@
|
|
|
22438
22454
|
|
|
22439
22455
|
return feature
|
|
22440
22456
|
}
|
|
22457
|
+
|
|
22441
22458
|
}
|
|
22442
22459
|
|
|
22443
22460
|
function findUTRs(exons, cdStart, cdEnd) {
|
|
@@ -23025,14 +23042,14 @@
|
|
|
23025
23042
|
// TODO -- align all feature attribute names with UCSC, an use specific column
|
|
23026
23043
|
for (let key of Object.keys(f)) {
|
|
23027
23044
|
const v = f[key];
|
|
23028
|
-
if (isString$
|
|
23045
|
+
if (isString$3(v) && v.toLowerCase() === term.toLowerCase()) {
|
|
23029
23046
|
return true
|
|
23030
23047
|
}
|
|
23031
23048
|
}
|
|
23032
23049
|
return false
|
|
23033
23050
|
});
|
|
23034
23051
|
if (matching.length > 0) {
|
|
23035
|
-
return matching.reduce((l, f) => (l.end - l.start) > (f.end - f.start) ? l : f,
|
|
23052
|
+
return matching.reduce((l, f) => (l.end - l.start) > (f.end - f.start) ? l : f, matching[0])
|
|
23036
23053
|
} else {
|
|
23037
23054
|
return undefined
|
|
23038
23055
|
}
|
|
@@ -23323,7 +23340,7 @@
|
|
|
23323
23340
|
class ZoomLevelHeader {
|
|
23324
23341
|
constructor(index, byteBuffer) {
|
|
23325
23342
|
this.index = index;
|
|
23326
|
-
this.reductionLevel = byteBuffer.
|
|
23343
|
+
this.reductionLevel = byteBuffer.getUInt();
|
|
23327
23344
|
this.reserved = byteBuffer.getInt();
|
|
23328
23345
|
this.dataOffset = byteBuffer.getLong();
|
|
23329
23346
|
this.indexOffset = byteBuffer.getLong();
|
|
@@ -26926,7 +26943,7 @@
|
|
|
26926
26943
|
let aaLetter;
|
|
26927
26944
|
if (undefined === aminoAcidLetter) {
|
|
26928
26945
|
|
|
26929
|
-
if(sequenceInterval.hasSequence(start, end)) {
|
|
26946
|
+
if (sequenceInterval.hasSequence(start, end)) {
|
|
26930
26947
|
|
|
26931
26948
|
const sequence = sequenceInterval.getSequence(start, end);
|
|
26932
26949
|
if (sequence && 3 === sequence.length) {
|
|
@@ -27062,7 +27079,8 @@
|
|
|
27062
27079
|
try {
|
|
27063
27080
|
ctx.save();
|
|
27064
27081
|
|
|
27065
|
-
|
|
27082
|
+
const labelField = this.config.labelField ? this.config.labelField : 'name';
|
|
27083
|
+
let name = feature[labelField];
|
|
27066
27084
|
if (name === undefined && feature.gene) name = feature.gene.name;
|
|
27067
27085
|
if (name === undefined) name = feature.id || feature.ID;
|
|
27068
27086
|
if (!name || name === '.') return
|
|
@@ -27095,20 +27113,13 @@
|
|
|
27095
27113
|
if (options.labelAllFeatures || xleft > lastLabelX || selected) {
|
|
27096
27114
|
options.rowLastLabelX[feature.row] = xright;
|
|
27097
27115
|
|
|
27098
|
-
|
|
27099
|
-
|
|
27100
|
-
|
|
27101
|
-
|
|
27102
|
-
|
|
27103
|
-
|
|
27104
|
-
|
|
27105
|
-
ctx.clearRect(
|
|
27106
|
-
centerX - textMetrics.width / 2 - 1,
|
|
27107
|
-
labelY - textMetrics.actualBoundingBoxAscent - 1,
|
|
27108
|
-
textMetrics.width + 2,
|
|
27109
|
-
textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent + 2);
|
|
27110
|
-
IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
|
|
27111
|
-
}
|
|
27116
|
+
ctx.clearRect(
|
|
27117
|
+
centerX - textMetrics.width / 2 - 1,
|
|
27118
|
+
labelY - textMetrics.actualBoundingBoxAscent - 1,
|
|
27119
|
+
textMetrics.width + 2,
|
|
27120
|
+
textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent + 2);
|
|
27121
|
+
IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
|
|
27122
|
+
|
|
27112
27123
|
}
|
|
27113
27124
|
|
|
27114
27125
|
} finally {
|
|
@@ -27522,7 +27533,11 @@
|
|
|
27522
27533
|
// If drawing amino acids fetch cached sequence interval. It is not needed if track does not support AA, but
|
|
27523
27534
|
// costs nothing since only a reference to a cached object is fetched.
|
|
27524
27535
|
if (bpPerPixel < aminoAcidSequenceRenderThreshold) {
|
|
27525
|
-
|
|
27536
|
+
// Restrict the range requested to the limits: 1-chromosome.bpLength
|
|
27537
|
+
const chromosome = this.browser.genome.getChromosome(referenceFrame.chr);
|
|
27538
|
+
const chromosomeEnd = chromosome.bpLength;
|
|
27539
|
+
options.sequenceInterval = this.browser.genome.getSequenceInterval(referenceFrame.chr,
|
|
27540
|
+
bpStart > 0 ? bpStart : 0, bpEnd > chromosomeEnd ? chromosomeEnd : bpEnd);
|
|
27526
27541
|
}
|
|
27527
27542
|
|
|
27528
27543
|
|
|
@@ -27649,7 +27664,7 @@
|
|
|
27649
27664
|
fd.name &&
|
|
27650
27665
|
fd.name.toLowerCase() === "name" &&
|
|
27651
27666
|
fd.value &&
|
|
27652
|
-
isString$
|
|
27667
|
+
isString$3(fd.value) &&
|
|
27653
27668
|
!fd.value.startsWith("<")) {
|
|
27654
27669
|
const href = infoURL.replace("$$", feature.name);
|
|
27655
27670
|
fd.value = `<a target=_blank href=${href}>${fd.value}</a>`;
|
|
@@ -28293,7 +28308,7 @@
|
|
|
28293
28308
|
async postInit() {
|
|
28294
28309
|
if(!this.featureSource) {
|
|
28295
28310
|
// This will be the case when restoring from a session
|
|
28296
|
-
const db = this.browser.genome.
|
|
28311
|
+
const db = this.browser.genome.ucscID; // TODO -- blat specific property
|
|
28297
28312
|
const url = this.browser.config["blatServerURL"];
|
|
28298
28313
|
const features = await blat({url, userSeq: this.sequence, db});
|
|
28299
28314
|
this._features = features;
|
|
@@ -28310,7 +28325,7 @@
|
|
|
28310
28325
|
if (undefined === this.table) {
|
|
28311
28326
|
|
|
28312
28327
|
const rows = this._features.map(f => [
|
|
28313
|
-
f.chr,
|
|
28328
|
+
this.browser.genome.getChromosomeDisplayName(f.chr),
|
|
28314
28329
|
(f.start + 1),
|
|
28315
28330
|
f.end,
|
|
28316
28331
|
f.strand,
|
|
@@ -28385,7 +28400,7 @@
|
|
|
28385
28400
|
|
|
28386
28401
|
try {
|
|
28387
28402
|
|
|
28388
|
-
const db = browser.genome.
|
|
28403
|
+
const db = browser.genome.ucscID; // TODO -- blat specific property
|
|
28389
28404
|
const url = browser.config["blatServerURL"] || defaultBlatServer;
|
|
28390
28405
|
const features = await blat({url, userSeq: sequence, db});
|
|
28391
28406
|
|
|
@@ -28627,7 +28642,7 @@
|
|
|
28627
28642
|
}
|
|
28628
28643
|
|
|
28629
28644
|
items.push({
|
|
28630
|
-
label: 'BLAT
|
|
28645
|
+
label: 'BLAT visible sequence',
|
|
28631
28646
|
click: async () => {
|
|
28632
28647
|
let sequence = await this.browser.genome.getSequence(chr, start, end);
|
|
28633
28648
|
if (sequence) {
|
|
@@ -30615,13 +30630,6 @@
|
|
|
30615
30630
|
this.trackStanzas = trackStanzas;
|
|
30616
30631
|
}
|
|
30617
30632
|
|
|
30618
|
-
findCytobandURL() {
|
|
30619
|
-
for (const t of this.trackStanzas) {
|
|
30620
|
-
if (t.name === "cytoBandIdeo" && t.hasProperty("bigDataUrl")) {
|
|
30621
|
-
return t.getProperty("bigDataUrl")
|
|
30622
|
-
}
|
|
30623
|
-
}
|
|
30624
|
-
}
|
|
30625
30633
|
|
|
30626
30634
|
getSupportedTrackCount() {
|
|
30627
30635
|
let count = 0;
|
|
@@ -30961,6 +30969,7 @@
|
|
|
30961
30969
|
|
|
30962
30970
|
const idMappings = new Map([
|
|
30963
30971
|
["hg38", "GCF_000001405.40"],
|
|
30972
|
+
["hg38_1kg", "GCF_000001405.40"],
|
|
30964
30973
|
["mm39", "GCF_000001635.27"],
|
|
30965
30974
|
["mm10", "GCF_000001635.26"],
|
|
30966
30975
|
["bosTau9", "GCF_002263795.1"],
|
|
@@ -30997,12 +31006,16 @@
|
|
|
30997
31006
|
this.genomeStanzas = genomeStanzas;
|
|
30998
31007
|
this.trackStanzas = trackStanzas;
|
|
30999
31008
|
this.groupStanzas = groupStanzas;
|
|
31009
|
+
this.cytobandStanza = null;
|
|
31000
31010
|
this.trackHubMap = new Map();
|
|
31001
31011
|
|
|
31002
31012
|
// trackStanzas will not be null if this is a "onefile" hub
|
|
31003
31013
|
if (trackStanzas) {
|
|
31004
31014
|
const genomeId = genomeStanzas[0].getProperty("genome"); // Assumption here this is a single genome hub
|
|
31005
31015
|
this.trackHubMap.set(genomeId, new TrackDbHub(trackStanzas, groupStanzas));
|
|
31016
|
+
|
|
31017
|
+
// Search for cytoband track. This supports a special but important case -- Genark assembly hubs
|
|
31018
|
+
this.cytobandStanza = this.trackStanzas.find(t => t.name === "cytoBandIdeo" && t.hasProperty("bigDataUrl")) || null;
|
|
31006
31019
|
}
|
|
31007
31020
|
}
|
|
31008
31021
|
|
|
@@ -31104,6 +31117,10 @@
|
|
|
31104
31117
|
config.twoBitBptURL = genomeStanza.getProperty("twoBitBptUrl");
|
|
31105
31118
|
}
|
|
31106
31119
|
|
|
31120
|
+
if(this.cytobandStanza){
|
|
31121
|
+
config.cytobandBbURL = this.cytobandStanza.getProperty("bigDataUrl");
|
|
31122
|
+
}
|
|
31123
|
+
|
|
31107
31124
|
if (this.hubStanza.hasProperty("longLabel")) {
|
|
31108
31125
|
config.description = this.hubStanza.getProperty("longLabel").replace("/", "\n");
|
|
31109
31126
|
} else {
|
|
@@ -31263,7 +31280,6 @@
|
|
|
31263
31280
|
if (t.hasProperty("searchTrix")) {
|
|
31264
31281
|
config.trixURL = t.getProperty("searchTrix");
|
|
31265
31282
|
}
|
|
31266
|
-
|
|
31267
31283
|
if (t.hasProperty("group")) {
|
|
31268
31284
|
config._group = t.getProperty("group");
|
|
31269
31285
|
if (this.groupPriorityMap && this.groupPriorityMap.has(config._group)) {
|
|
@@ -31272,6 +31288,12 @@
|
|
|
31272
31288
|
this.groupPriorityMap.set(config._group, nextPriority);
|
|
31273
31289
|
}
|
|
31274
31290
|
}
|
|
31291
|
+
const labelFields = t.hasProperty("defaultLabelFields") ?
|
|
31292
|
+
t.getProperty("defaultLabelFields") :
|
|
31293
|
+
t.getProperty("labelFields");
|
|
31294
|
+
if (labelFields) {
|
|
31295
|
+
config.labelField = labelFields.split(",")[0];
|
|
31296
|
+
}
|
|
31275
31297
|
|
|
31276
31298
|
return config
|
|
31277
31299
|
}
|
|
@@ -31412,9 +31434,9 @@
|
|
|
31412
31434
|
}
|
|
31413
31435
|
|
|
31414
31436
|
|
|
31415
|
-
const
|
|
31416
|
-
const key = line.substring(0,
|
|
31417
|
-
let value = line.substring(
|
|
31437
|
+
const index = line.indexOf(' ');
|
|
31438
|
+
const key = line.substring(0, index).trim();
|
|
31439
|
+
let value = line.substring(index + 1).trim();
|
|
31418
31440
|
|
|
31419
31441
|
if (key === "type") {
|
|
31420
31442
|
// The "type" property contains format and sometimes other information. For example, data range
|
|
@@ -31497,8 +31519,8 @@
|
|
|
31497
31519
|
return host
|
|
31498
31520
|
}
|
|
31499
31521
|
|
|
31500
|
-
const DEFAULT_GENOMES_URL = "https://igv.org/genomes/
|
|
31501
|
-
const BACKUP_GENOMES_URL = "https://raw.githubusercontent.com/igvteam/igv-
|
|
31522
|
+
const DEFAULT_GENOMES_URL = "https://igv.org/genomes/genomes3.json";
|
|
31523
|
+
const BACKUP_GENOMES_URL = "https://raw.githubusercontent.com/igvteam/igv-data/refs/heads/main/genomes/web/genomes.json";
|
|
31502
31524
|
|
|
31503
31525
|
const GenomeUtils = {
|
|
31504
31526
|
|
|
@@ -31523,7 +31545,7 @@
|
|
|
31523
31545
|
} catch (error) {
|
|
31524
31546
|
try {
|
|
31525
31547
|
console.error("Error initializing default genomes:", error);
|
|
31526
|
-
const jsonArray = await igvxhr.loadJson(BACKUP_GENOMES_URL, {timeout:
|
|
31548
|
+
const jsonArray = await igvxhr.loadJson(BACKUP_GENOMES_URL, {timeout: 10000});
|
|
31527
31549
|
processJson(jsonArray, table);
|
|
31528
31550
|
} catch (e) {
|
|
31529
31551
|
console.error("Error initializing backup genomes:", error);
|
|
@@ -31553,7 +31575,7 @@
|
|
|
31553
31575
|
expandReference: async function (alert, idOrConfig) {
|
|
31554
31576
|
|
|
31555
31577
|
// idOrConfig might be a json string? I'm actually not sure how this arises.
|
|
31556
|
-
if (isString$
|
|
31578
|
+
if (isString$3(idOrConfig) && idOrConfig.startsWith("{")) {
|
|
31557
31579
|
try {
|
|
31558
31580
|
idOrConfig = JSON.parse(idOrConfig);
|
|
31559
31581
|
} catch (e) {
|
|
@@ -31562,7 +31584,7 @@
|
|
|
31562
31584
|
}
|
|
31563
31585
|
|
|
31564
31586
|
let genomeID;
|
|
31565
|
-
if (isString$
|
|
31587
|
+
if (isString$3(idOrConfig)) {
|
|
31566
31588
|
genomeID = idOrConfig;
|
|
31567
31589
|
} else if (idOrConfig.genome) {
|
|
31568
31590
|
genomeID = idOrConfig.genome;
|
|
@@ -32508,7 +32530,7 @@
|
|
|
32508
32530
|
let track = this.trackView.track;
|
|
32509
32531
|
const dataList = track.popupData(clickState);
|
|
32510
32532
|
|
|
32511
|
-
const popupClickHandlerResult = this.browser.fireEvent('trackclick', [track, dataList]);
|
|
32533
|
+
const popupClickHandlerResult = this.browser.fireEvent('trackclick', [track, dataList, clickState.genomicLocation]);
|
|
32512
32534
|
|
|
32513
32535
|
let content;
|
|
32514
32536
|
if (undefined === popupClickHandlerResult || true === popupClickHandlerResult) {
|
|
@@ -40998,6 +41020,9 @@
|
|
|
40998
41020
|
return true
|
|
40999
41021
|
}
|
|
41000
41022
|
|
|
41023
|
+
/**
|
|
41024
|
+
* Track for segmented copy number, mut, maf and shoebox files.
|
|
41025
|
+
*/
|
|
41001
41026
|
class SegTrack extends TrackBase {
|
|
41002
41027
|
|
|
41003
41028
|
#sortDirections = new Map()
|
|
@@ -41145,7 +41170,10 @@
|
|
|
41145
41170
|
}, e);
|
|
41146
41171
|
}
|
|
41147
41172
|
|
|
41148
|
-
menuItems.push({
|
|
41173
|
+
menuItems.push({
|
|
41174
|
+
element: createElementWithString('<div>Set color scale threshold</div>'),
|
|
41175
|
+
dialog: dialogPresentationHandler
|
|
41176
|
+
});
|
|
41149
41177
|
}
|
|
41150
41178
|
|
|
41151
41179
|
menuItems.push('<hr/>');
|
|
@@ -41176,12 +41204,75 @@
|
|
|
41176
41204
|
|
|
41177
41205
|
getSamples() {
|
|
41178
41206
|
return {
|
|
41179
|
-
names: this.
|
|
41207
|
+
names: this.filteredSampleKeys,
|
|
41180
41208
|
height: this.sampleHeight,
|
|
41181
41209
|
yOffset: 0
|
|
41182
41210
|
}
|
|
41183
41211
|
}
|
|
41184
41212
|
|
|
41213
|
+
/**
|
|
41214
|
+
* Set the sample filter object. This is used to filter samples from the set based on values over a specified
|
|
41215
|
+
* genomic region. The values compared depend on the track data type:
|
|
41216
|
+
* - "seg" and "shoebox" -- average value over the region
|
|
41217
|
+
* - "mut" and "maf" -- count of features overlapping the region
|
|
41218
|
+
*
|
|
41219
|
+
* The method is asynchronous because it may need to fetch data from the server to compute the scores.
|
|
41220
|
+
* Computed scores are stored and used to filter the sample keys on demand.
|
|
41221
|
+
*
|
|
41222
|
+
* @param filterObject
|
|
41223
|
+
* @returns {Promise<void>}
|
|
41224
|
+
*/
|
|
41225
|
+
async setSampleFilter(filterObject) {
|
|
41226
|
+
if (!filterObject) {
|
|
41227
|
+
this.config.filterObject = undefined;
|
|
41228
|
+
this.filterObject = undefined;
|
|
41229
|
+
this.trackView.repaintViews();
|
|
41230
|
+
} else {
|
|
41231
|
+
const filterObjectCopy = Object.assign({}, filterObject);
|
|
41232
|
+
this.config.filterObject = filterObjectCopy;
|
|
41233
|
+
|
|
41234
|
+
filterObject.scores = await this.computeRegionScores(filterObject);
|
|
41235
|
+
this.filterObject = filterObject;
|
|
41236
|
+
this.trackView.checkContentHeight();
|
|
41237
|
+
this.trackView.repaintViews();
|
|
41238
|
+
}
|
|
41239
|
+
// TODO - store filter object in session
|
|
41240
|
+
}
|
|
41241
|
+
|
|
41242
|
+
|
|
41243
|
+
/**
|
|
41244
|
+
* Filter function for sample keys.
|
|
41245
|
+
*
|
|
41246
|
+
* @param sampleKey
|
|
41247
|
+
* @returns {boolean}
|
|
41248
|
+
*/
|
|
41249
|
+
filter(sampleKey) {
|
|
41250
|
+
if (this.filterObject) {
|
|
41251
|
+
const filterObject = this.filterObject;
|
|
41252
|
+
const scores = filterObject.scores;
|
|
41253
|
+
const score = scores[sampleKey];
|
|
41254
|
+
|
|
41255
|
+
if (this.type === 'seg') {
|
|
41256
|
+
if (filterObject.op === '>') {
|
|
41257
|
+
return score > filterObject.value
|
|
41258
|
+
} else if (filterObject.op === '<') {
|
|
41259
|
+
return score < filterObject.value
|
|
41260
|
+
}
|
|
41261
|
+
} else if (this.type === 'mut' || this.type === 'maf') {
|
|
41262
|
+
return 'HAS' === filterObject.op ? score : !score
|
|
41263
|
+
}
|
|
41264
|
+
}
|
|
41265
|
+
// else if (this.config.sampleFilter) {
|
|
41266
|
+
// return this.config.sampleFilter(sampleKey)
|
|
41267
|
+
// }
|
|
41268
|
+
return true
|
|
41269
|
+
}
|
|
41270
|
+
|
|
41271
|
+
get filteredSampleKeys() {
|
|
41272
|
+
return this.sampleKeys.filter(sampleKey => this.filter(sampleKey))
|
|
41273
|
+
}
|
|
41274
|
+
|
|
41275
|
+
|
|
41185
41276
|
async getFeatures(chr, start, end) {
|
|
41186
41277
|
const features = await this.featureSource.getFeatures({chr, start, end});
|
|
41187
41278
|
// New segments could conceivably add new samples
|
|
@@ -41189,8 +41280,10 @@
|
|
|
41189
41280
|
|
|
41190
41281
|
if (this.initialSort) {
|
|
41191
41282
|
const sort = this.initialSort;
|
|
41283
|
+
|
|
41192
41284
|
if (sort.option === undefined || sort.option.toUpperCase() === "VALUE") {
|
|
41193
|
-
|
|
41285
|
+
const sortFeatures = (sort.chr === chr && sort.start >= start && sort.end <= end) ? features : undefined;
|
|
41286
|
+
this.sortByValue(sort, sortFeatures);
|
|
41194
41287
|
} else if ("ATTRIBUTE" === sort.option.toUpperCase() && sort.attribute) {
|
|
41195
41288
|
const sortDirection = "DESC" === sort.direction ? 1 : -1;
|
|
41196
41289
|
this.sortByAttribute(sort.attribute, sortDirection);
|
|
@@ -41205,6 +41298,7 @@
|
|
|
41205
41298
|
|
|
41206
41299
|
IGVGraphics.fillRect(context, 0, pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
41207
41300
|
|
|
41301
|
+
|
|
41208
41302
|
if (features && features.length > 0) {
|
|
41209
41303
|
|
|
41210
41304
|
this.checkForLog(features);
|
|
@@ -41216,14 +41310,15 @@
|
|
|
41216
41310
|
|
|
41217
41311
|
// Create a map for fast id -> row lookup
|
|
41218
41312
|
const samples = {};
|
|
41219
|
-
|
|
41313
|
+
const filteredKeys = this.filteredSampleKeys;
|
|
41314
|
+
filteredKeys.forEach(function (id, index) {
|
|
41220
41315
|
samples[id] = index;
|
|
41221
41316
|
});
|
|
41222
41317
|
|
|
41223
41318
|
let border;
|
|
41224
41319
|
switch (this.displayMode) {
|
|
41225
41320
|
case "FILL":
|
|
41226
|
-
this.sampleHeight = pixelHeight /
|
|
41321
|
+
this.sampleHeight = pixelHeight / filteredKeys.length;
|
|
41227
41322
|
border = 0;
|
|
41228
41323
|
break
|
|
41229
41324
|
|
|
@@ -41361,7 +41456,7 @@
|
|
|
41361
41456
|
if (!features) return 0
|
|
41362
41457
|
const sampleHeight = ("SQUISHED" === this.displayMode) ? this.squishedRowHeight : this.expandedRowHeight;
|
|
41363
41458
|
this.updateSampleKeys(features);
|
|
41364
|
-
return this.
|
|
41459
|
+
return this.filteredSampleKeys.length * sampleHeight
|
|
41365
41460
|
}
|
|
41366
41461
|
|
|
41367
41462
|
/**
|
|
@@ -41370,16 +41465,38 @@
|
|
|
41370
41465
|
async sortByValue(sort, featureList) {
|
|
41371
41466
|
|
|
41372
41467
|
const chr = sort.chr;
|
|
41468
|
+
const start = sort.position !== undefined ? sort.position - 1 : sort.start;
|
|
41469
|
+
const end = sort.end === undefined ? start + 1 : sort.end;
|
|
41470
|
+
const scores = await this.computeRegionScores({chr, start, end}, featureList);
|
|
41471
|
+
const d2 = (sort.direction === "ASC" ? 1 : -1);
|
|
41472
|
+
|
|
41473
|
+
this.sampleKeys.sort(function (a, b) {
|
|
41474
|
+
let s1 = scores[a];
|
|
41475
|
+
let s2 = scores[b];
|
|
41476
|
+
if (!s1) s1 = d2 * Number.MAX_VALUE;
|
|
41477
|
+
if (!s2) s2 = d2 * Number.MAX_VALUE;
|
|
41478
|
+
if (s1 === s2) return 0
|
|
41479
|
+
else if (s1 > s2) return d2
|
|
41480
|
+
else return d2 * -1
|
|
41481
|
+
});
|
|
41482
|
+
|
|
41483
|
+
this.config.sort = sort;
|
|
41484
|
+
this.trackView.repaintViews();
|
|
41485
|
+
}
|
|
41486
|
+
|
|
41487
|
+
|
|
41488
|
+
async computeRegionScores(filterObject, featureList) {
|
|
41489
|
+
|
|
41490
|
+
const chr = filterObject.chr;
|
|
41373
41491
|
let start, end;
|
|
41374
|
-
if (
|
|
41375
|
-
start =
|
|
41492
|
+
if (filterObject.position) {
|
|
41493
|
+
start = filterObject.position - 1;
|
|
41376
41494
|
end = start + 1;
|
|
41377
41495
|
} else {
|
|
41378
|
-
start =
|
|
41379
|
-
end =
|
|
41496
|
+
start = filterObject.start;
|
|
41497
|
+
end = filterObject.end;
|
|
41380
41498
|
}
|
|
41381
41499
|
|
|
41382
|
-
|
|
41383
41500
|
if (!featureList) {
|
|
41384
41501
|
featureList = await this.featureSource.getFeatures({chr, start, end});
|
|
41385
41502
|
}
|
|
@@ -41388,62 +41505,40 @@
|
|
|
41388
41505
|
this.updateSampleKeys(featureList);
|
|
41389
41506
|
|
|
41390
41507
|
const scores = {};
|
|
41391
|
-
const
|
|
41508
|
+
const bpLength = end - start + 1;
|
|
41509
|
+
|
|
41510
|
+
const mutationTypes = filterObject.value ? new Set(filterObject.value) : undefined;
|
|
41511
|
+
|
|
41512
|
+
for (let segment of featureList) {
|
|
41513
|
+
if (segment.end < start) continue
|
|
41514
|
+
if (segment.start > end) break
|
|
41515
|
+
const sampleKey = segment.sampleKey || segment.sample;
|
|
41516
|
+
|
|
41517
|
+
if ("mut" === this.type) {
|
|
41518
|
+
if (mutationTypes) {
|
|
41519
|
+
const mutationType = segment.getAttribute("Variant_Classification");
|
|
41520
|
+
if (mutationTypes.has(mutationType)) {
|
|
41521
|
+
// Just count features overlapping region per sample
|
|
41522
|
+
scores[sampleKey] = (scores[sampleKey] || 0) + 1;
|
|
41523
|
+
}
|
|
41524
|
+
} else {
|
|
41525
|
+
// Just count features overlapping region per sample
|
|
41526
|
+
scores[sampleKey] = (scores[sampleKey] || 0) + 1;
|
|
41527
|
+
}
|
|
41528
|
+
} else {
|
|
41392
41529
|
|
|
41393
|
-
const sortSeg = () => {
|
|
41394
|
-
// Compute weighted average score for each sample
|
|
41395
|
-
const bpLength = end - start + 1;
|
|
41396
|
-
for (let segment of featureList) {
|
|
41397
|
-
if (segment.end < start) continue
|
|
41398
|
-
if (segment.start > end) break
|
|
41399
41530
|
const min = Math.max(start, segment.start);
|
|
41400
41531
|
const max = Math.min(end, segment.end);
|
|
41401
41532
|
const f = (max - min) / bpLength;
|
|
41402
|
-
|
|
41403
|
-
|
|
41404
|
-
scores[sampleKey] = s + f * segment.value;
|
|
41405
|
-
}
|
|
41406
|
-
|
|
41407
|
-
// Now sort sample names by score
|
|
41408
|
-
this.sampleKeys.sort(function (a, b) {
|
|
41409
|
-
let s1 = scores[a];
|
|
41410
|
-
let s2 = scores[b];
|
|
41411
|
-
if (!s1) s1 = d2 * Number.MAX_VALUE;
|
|
41412
|
-
if (!s2) s2 = d2 * Number.MAX_VALUE;
|
|
41413
|
-
if (s1 === s2) return 0
|
|
41414
|
-
else if (s1 > s2) return d2
|
|
41415
|
-
else return d2 * -1
|
|
41416
|
-
});
|
|
41417
|
-
};
|
|
41418
|
-
|
|
41419
|
-
const sortMut = () => {
|
|
41420
|
-
// Compute weighted average score for each sample
|
|
41421
|
-
for (let segment of featureList) {
|
|
41422
|
-
if (segment.end < start) continue
|
|
41423
|
-
if (segment.start > end) break
|
|
41424
|
-
const sampleKey = segment.sampleKey || segment.sample;
|
|
41425
|
-
if (!scores.hasOwnProperty(sampleKey) || segment.value.localeCompare(scores[sampleKey]) > 0) {
|
|
41426
|
-
scores[sampleKey] = segment.value;
|
|
41427
|
-
}
|
|
41428
|
-
}
|
|
41429
|
-
// Now sort sample names by score
|
|
41430
|
-
this.sampleKeys.sort(function (a, b) {
|
|
41431
|
-
let sa = scores[a] || "";
|
|
41432
|
-
let sb = scores[b] || "";
|
|
41433
|
-
return d2 * (sa.localeCompare(sb))
|
|
41434
|
-
});
|
|
41435
|
-
};
|
|
41436
|
-
|
|
41437
|
-
if ("mut" === this.type) {
|
|
41438
|
-
sortMut();
|
|
41439
|
-
} else {
|
|
41440
|
-
sortSeg();
|
|
41533
|
+
scores[sampleKey] = (scores[sampleKey] || 0) + f * segment.value;
|
|
41534
|
+
}
|
|
41441
41535
|
}
|
|
41442
41536
|
|
|
41443
|
-
|
|
41537
|
+
return scores
|
|
41444
41538
|
|
|
41445
41539
|
}
|
|
41446
41540
|
|
|
41541
|
+
|
|
41447
41542
|
sortByAttribute(attribute, sortDirection) {
|
|
41448
41543
|
|
|
41449
41544
|
this.sampleKeys = this.browser.sampleInfo.getSortedSampleKeysByAttribute(this.sampleKeys, attribute, sortDirection);
|
|
@@ -41512,7 +41607,7 @@
|
|
|
41512
41607
|
const dirLabel = direction === "DESC" ? "descending" : "ascending";
|
|
41513
41608
|
const sortLabel = this.type === 'seg' || this.type === 'shoebox' ?
|
|
41514
41609
|
`Sort by value (${dirLabel})` :
|
|
41515
|
-
`Sort by
|
|
41610
|
+
`Sort by count (${dirLabel})`;
|
|
41516
41611
|
return {
|
|
41517
41612
|
label: sortLabel,
|
|
41518
41613
|
click: () => {
|
|
@@ -41524,7 +41619,6 @@
|
|
|
41524
41619
|
end: Math.floor(genomicLocation + bpWidth)
|
|
41525
41620
|
};
|
|
41526
41621
|
sortHandler(sort);
|
|
41527
|
-
this.config.sort = sort;
|
|
41528
41622
|
}
|
|
41529
41623
|
}
|
|
41530
41624
|
})
|
|
@@ -41694,13 +41788,13 @@
|
|
|
41694
41788
|
}
|
|
41695
41789
|
}
|
|
41696
41790
|
|
|
41697
|
-
popupData(genomicLocation) {
|
|
41791
|
+
popupData(genomicLocation, hiddenTags, showTags) {
|
|
41698
41792
|
|
|
41699
|
-
let nameValues = this.firstAlignment.popupData(genomicLocation);
|
|
41793
|
+
let nameValues = this.firstAlignment.popupData(genomicLocation, hiddenTags, showTags);
|
|
41700
41794
|
|
|
41701
41795
|
if (this.secondAlignment) {
|
|
41702
41796
|
nameValues.push("-------------------------------");
|
|
41703
|
-
nameValues = nameValues.concat(this.secondAlignment.popupData(genomicLocation));
|
|
41797
|
+
nameValues = nameValues.concat(this.secondAlignment.popupData(genomicLocation, hiddenTags, showTags));
|
|
41704
41798
|
}
|
|
41705
41799
|
return nameValues
|
|
41706
41800
|
}
|
|
@@ -43414,7 +43508,7 @@
|
|
|
43414
43508
|
isNegativeStrand() {
|
|
43415
43509
|
return (this.flags & READ_STRAND_FLAG$2) !== 0
|
|
43416
43510
|
}
|
|
43417
|
-
|
|
43511
|
+
|
|
43418
43512
|
isMateNegativeStrand() {
|
|
43419
43513
|
return (this.flags & MATE_STRAND_FLAG$2) !== 0
|
|
43420
43514
|
}
|
|
@@ -43462,7 +43556,7 @@
|
|
|
43462
43556
|
return (genomicLocation >= s && genomicLocation <= (s + l))
|
|
43463
43557
|
}
|
|
43464
43558
|
|
|
43465
|
-
popupData(genomicLocation) {
|
|
43559
|
+
popupData(genomicLocation, hiddenTags, showTags) {
|
|
43466
43560
|
|
|
43467
43561
|
// if the user clicks on a base next to an insertion, show just the
|
|
43468
43562
|
// inserted bases in a popup (like in desktop IGV).
|
|
@@ -43545,15 +43639,20 @@
|
|
|
43545
43639
|
}
|
|
43546
43640
|
}
|
|
43547
43641
|
|
|
43548
|
-
const hiddenTags = new Set(['SA', 'MD']);
|
|
43549
43642
|
nameValues.push('<hr/>');
|
|
43550
43643
|
for (let key in tagDict) {
|
|
43551
|
-
if (
|
|
43644
|
+
if (showTags?.has(key)) {
|
|
43645
|
+
nameValues.push({name: key, value: tagDict[key]});
|
|
43646
|
+
} else if (showTags) {
|
|
43647
|
+
hiddenTags.add(key);
|
|
43648
|
+
} else if (!hiddenTags.has(key)) {
|
|
43552
43649
|
nameValues.push({name: key, value: tagDict[key]});
|
|
43553
43650
|
}
|
|
43554
43651
|
}
|
|
43555
43652
|
|
|
43556
|
-
|
|
43653
|
+
if (hiddenTags && hiddenTags.size > 0) {
|
|
43654
|
+
nameValues.push({name: 'Hidden Tags', value: Array.from(hiddenTags).join(", ")});
|
|
43655
|
+
}
|
|
43557
43656
|
|
|
43558
43657
|
nameValues.push('<hr/>');
|
|
43559
43658
|
nameValues.push({name: 'Genomic Location: ', value: numberFormatter$1(1 + genomicLocation)});
|
|
@@ -43561,18 +43660,18 @@
|
|
|
43561
43660
|
nameValues.push({name: 'Base Quality:', value: this.readBaseQualityAt(genomicLocation)});
|
|
43562
43661
|
|
|
43563
43662
|
const bmSets = this.getBaseModificationSets();
|
|
43564
|
-
if(bmSets) {
|
|
43663
|
+
if (bmSets) {
|
|
43565
43664
|
const i = this.positionToReadIndex(genomicLocation);
|
|
43566
|
-
if(undefined !== i) {
|
|
43665
|
+
if (undefined !== i) {
|
|
43567
43666
|
let found = false;
|
|
43568
43667
|
for (let bmSet of bmSets) {
|
|
43569
43668
|
if (bmSet.containsPosition(i)) {
|
|
43570
|
-
if(!found) {
|
|
43669
|
+
if (!found) {
|
|
43571
43670
|
nameValues.push('<hr/>');
|
|
43572
43671
|
nameValues.push('<b>Base modifications:</b>');
|
|
43573
43672
|
found = true;
|
|
43574
43673
|
}
|
|
43575
|
-
const lh = Math.round((100/255) * byteToUnsignedInt(bmSet.likelihoods.get(i)));
|
|
43674
|
+
const lh = Math.round((100 / 255) * byteToUnsignedInt(bmSet.likelihoods.get(i)));
|
|
43576
43675
|
nameValues.push(`${bmSet.fullName()} @ likelihood = ${lh}%`);
|
|
43577
43676
|
}
|
|
43578
43677
|
}
|
|
@@ -43662,7 +43761,7 @@
|
|
|
43662
43761
|
const mm = this.tagDict["MM"] || this.tagDict["Mm"];
|
|
43663
43762
|
const ml = this.tagDict["ML"] || this.tagDict["Ml"];
|
|
43664
43763
|
|
|
43665
|
-
if (isString$
|
|
43764
|
+
if (isString$3(mm) && (!ml || Array.isArray(ml))) { // minimal validation, 10X uses these reserved tags for something completely different
|
|
43666
43765
|
if (mm.length === 0) {
|
|
43667
43766
|
this.baseModificationSets = EMPTY_SET;
|
|
43668
43767
|
} else {
|
|
@@ -43675,7 +43774,7 @@
|
|
|
43675
43774
|
return this.baseModificationSets
|
|
43676
43775
|
}
|
|
43677
43776
|
|
|
43678
|
-
|
|
43777
|
+
getGroupValue(groupBy, tag, expectedPairOrientation) {
|
|
43679
43778
|
|
|
43680
43779
|
const al = this;
|
|
43681
43780
|
switch (groupBy) {
|
|
@@ -43712,7 +43811,7 @@
|
|
|
43712
43811
|
}
|
|
43713
43812
|
}
|
|
43714
43813
|
|
|
43715
|
-
positionToReadIndex(
|
|
43814
|
+
positionToReadIndex(position) {
|
|
43716
43815
|
const block = blockAtGenomicLocation(this.blocks, position);
|
|
43717
43816
|
if (block) {
|
|
43718
43817
|
return (position - block.start) + block.seqOffset
|
|
@@ -45691,7 +45790,7 @@
|
|
|
45691
45790
|
|
|
45692
45791
|
function inferIndexPath(url, extension) {
|
|
45693
45792
|
|
|
45694
|
-
if (isString$
|
|
45793
|
+
if (isString$3(url)) {
|
|
45695
45794
|
if (url.includes("?")) {
|
|
45696
45795
|
const idx = url.indexOf("?");
|
|
45697
45796
|
return url.substring(0, idx) + "." + extension + url.substring(idx)
|
|
@@ -45850,7 +45949,7 @@
|
|
|
45850
45949
|
this.bamReader = new CramReader(config, genome, browser);
|
|
45851
45950
|
} else {
|
|
45852
45951
|
if (!this.config.indexURL && config.indexed !== false) {
|
|
45853
|
-
if (isString$
|
|
45952
|
+
if (isString$3(this.config.url)) {
|
|
45854
45953
|
const indexPath = inferIndexPath(this.config.url, "bai");
|
|
45855
45954
|
if (indexPath) {
|
|
45856
45955
|
console.warn(`Warning: no indexURL specified for ${this.config.url}. Guessing ${indexPath}`);
|
|
@@ -48162,7 +48261,7 @@
|
|
|
48162
48261
|
highlightColor: undefined,
|
|
48163
48262
|
minTLEN: undefined,
|
|
48164
48263
|
maxTLEN: undefined,
|
|
48165
|
-
tagColorPallete: "Set1"
|
|
48264
|
+
tagColorPallete: "Set1",
|
|
48166
48265
|
}
|
|
48167
48266
|
|
|
48168
48267
|
_colorTables = new Map()
|
|
@@ -48177,6 +48276,18 @@
|
|
|
48177
48276
|
this.colorTable = new ColorTable(config.tagColorTable);
|
|
48178
48277
|
}
|
|
48179
48278
|
|
|
48279
|
+
// Only one of showTags / hideTags should be specified. If both are specified showTags takes precedence.
|
|
48280
|
+
if (config.showTags && config.hideTags) {
|
|
48281
|
+
console.warn("Both showTags and hideTags specified. showTags will be used.");
|
|
48282
|
+
}
|
|
48283
|
+
if (config.showTags) {
|
|
48284
|
+
this.showTags = new Set(config.showTags);
|
|
48285
|
+
this.hiddenTags = new Set();
|
|
48286
|
+
} else {
|
|
48287
|
+
this.hiddenTags = new Set(config.hideTags || ["SA", "MD"]);
|
|
48288
|
+
}
|
|
48289
|
+
|
|
48290
|
+
|
|
48180
48291
|
// Backward compatibility overrides
|
|
48181
48292
|
if (config.largeFragmentLengthColor) this.largeTLENColor = config.largeFragmentLengthColor;
|
|
48182
48293
|
if (config.pairOrienation) this.expectedPairOrientation = config.pairOrientation;
|
|
@@ -48737,7 +48848,7 @@
|
|
|
48737
48848
|
|
|
48738
48849
|
popupData(clickState) {
|
|
48739
48850
|
const clickedObject = this.getClickedObject(clickState);
|
|
48740
|
-
return clickedObject
|
|
48851
|
+
return clickedObject?.popupData(clickState.genomicLocation, this.hiddenTags, this.showTags)
|
|
48741
48852
|
};
|
|
48742
48853
|
|
|
48743
48854
|
/**
|
|
@@ -48768,7 +48879,10 @@
|
|
|
48768
48879
|
colorByMenuItems.push({key: 'tlen', label: 'insert size (TLEN)'});
|
|
48769
48880
|
colorByMenuItems.push({key: 'unexpectedPair', label: 'pair orientation & insert size (TLEN)'});
|
|
48770
48881
|
}
|
|
48771
|
-
|
|
48882
|
+
if(this.colorBy && this.colorBy.startsWith("tag:")) {
|
|
48883
|
+
colorByMenuItems.push({key: this.colorBy, label: this.colorBy});
|
|
48884
|
+
}
|
|
48885
|
+
colorByMenuItems.push({key: 'tag', label: 'tag...'});
|
|
48772
48886
|
for (let item of colorByMenuItems) {
|
|
48773
48887
|
const selected = (this.colorBy === undefined && item.key === 'none') || this.colorBy === item.key;
|
|
48774
48888
|
menuItems.push(this.colorByCB(item, selected));
|
|
@@ -49284,7 +49398,7 @@
|
|
|
49284
49398
|
|
|
49285
49399
|
if (seqstring.length < maxSequenceSize$1) {
|
|
49286
49400
|
list.push({
|
|
49287
|
-
label: 'BLAT
|
|
49401
|
+
label: 'BLAT visible sequence',
|
|
49288
49402
|
click: () => {
|
|
49289
49403
|
const sequence = clickedAlignment.isNegativeStrand() ? reverseComplementSequence(seqstring) : seqstring;
|
|
49290
49404
|
const name = `${clickedAlignment.readName} - blat`;
|
|
@@ -49494,14 +49608,19 @@
|
|
|
49494
49608
|
case "tag":
|
|
49495
49609
|
const tagValue = alignment.tags()[tag];
|
|
49496
49610
|
if (tagValue !== undefined) {
|
|
49497
|
-
|
|
49611
|
+
|
|
49612
|
+
// If the tag value can be interpreted as a color, use it
|
|
49613
|
+
if(typeof tagValue.startsWith === 'function') {
|
|
49498
49614
|
color = IGVColor.createColorStringSafe(tagValue);
|
|
49499
49615
|
}
|
|
49500
|
-
if (!this.colorTable) {
|
|
49501
|
-
this.colorTable = new PaletteColorTable(this.tagColorPallete);
|
|
49502
|
-
}
|
|
49503
|
-
color = this.colorTable.getColor(tagValue);
|
|
49504
49616
|
|
|
49617
|
+
// Tag value is not a color, use a color table
|
|
49618
|
+
if (!color) {
|
|
49619
|
+
if (!this.colorTable) {
|
|
49620
|
+
this.colorTable = new PaletteColorTable(this.tagColorPallete);
|
|
49621
|
+
}
|
|
49622
|
+
color = this.colorTable.getColor(tagValue);
|
|
49623
|
+
}
|
|
49505
49624
|
}
|
|
49506
49625
|
break
|
|
49507
49626
|
}
|
|
@@ -65718,7 +65837,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
65718
65837
|
* THE SOFTWARE.
|
|
65719
65838
|
*/
|
|
65720
65839
|
|
|
65721
|
-
const isString = isString$
|
|
65840
|
+
const isString$1 = isString$3;
|
|
65722
65841
|
|
|
65723
65842
|
const DEFAULT_VISIBILITY_WINDOW = 1000000;
|
|
65724
65843
|
const TOP_MARGIN = 10;
|
|
@@ -65841,7 +65960,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
65841
65960
|
}
|
|
65842
65961
|
if (undefined === this.visibilityWindow && this.config.indexed !== false) {
|
|
65843
65962
|
const fn = isFile(this.config.url) ? this.config.url.name : this.config.url;
|
|
65844
|
-
if (isString(fn) && fn.toLowerCase().includes("gnomad")) {
|
|
65963
|
+
if (isString$1(fn) && fn.toLowerCase().includes("gnomad")) {
|
|
65845
65964
|
this.visibilityWindow = 1000; // these are known to be very dense
|
|
65846
65965
|
} else if (typeof this.featureSource.defaultVisibilityWindow === 'function') {
|
|
65847
65966
|
this.visibilityWindow = await this.featureSource.defaultVisibilityWindow();
|
|
@@ -69725,6 +69844,9 @@ ${indent}columns: ${matrix.columns}
|
|
|
69725
69844
|
['image', (config, browser) => new ImageTrack(config, browser)]
|
|
69726
69845
|
]);
|
|
69727
69846
|
|
|
69847
|
+
function knownTrackTypes () {
|
|
69848
|
+
return new Set(trackFunctions.keys())
|
|
69849
|
+
}
|
|
69728
69850
|
|
|
69729
69851
|
/**
|
|
69730
69852
|
* Return a track of the given type, passing configuration and a point to the IGV "Browser" object to its constructor function*
|
|
@@ -70217,7 +70339,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
70217
70339
|
})
|
|
70218
70340
|
}
|
|
70219
70341
|
|
|
70220
|
-
const _version = "3.
|
|
70342
|
+
const _version = "3.4.1";
|
|
70221
70343
|
function version() {
|
|
70222
70344
|
return _version
|
|
70223
70345
|
}
|
|
@@ -70268,7 +70390,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
70268
70390
|
if (this.select.value.trim().toLowerCase() === "all" || this.select.value === "*") {
|
|
70269
70391
|
if (browser.genome.wholeGenomeView) {
|
|
70270
70392
|
const wgChr = browser.genome.getChromosome("all");
|
|
70271
|
-
|
|
70393
|
+
browser.updateLoci([{chr: "all", start: 0, end: wgChr.bpLength}]);
|
|
70272
70394
|
}
|
|
70273
70395
|
} else {
|
|
70274
70396
|
const chromosome = await browser.genome.loadChromosome(this.select.value);
|
|
@@ -72073,6 +72195,26 @@ ${indent}columns: ${matrix.columns}
|
|
|
72073
72195
|
}
|
|
72074
72196
|
|
|
72075
72197
|
|
|
72198
|
+
const found = this.browser.findTracks(track => typeof track.sortByValue === 'function');
|
|
72199
|
+
if (found.length > 0) {
|
|
72200
|
+
const { chr, start, end } = feature;
|
|
72201
|
+
items.push(
|
|
72202
|
+
'<hr/>',
|
|
72203
|
+
{
|
|
72204
|
+
label: 'Sort by value (ascending)',
|
|
72205
|
+
click: () => Promise.all(found.map(track => track.sortByValue({ option: 'VALUE', direction: 'ASC', chr, start, end })))
|
|
72206
|
+
});
|
|
72207
|
+
|
|
72208
|
+
items.push(
|
|
72209
|
+
'<hr/>',
|
|
72210
|
+
{
|
|
72211
|
+
label: 'Sort by value (descending)',
|
|
72212
|
+
click: () => Promise.all(found.map(track => track.sortByValue({ option: 'VALUE', direction: 'DESC', chr, start, end })))
|
|
72213
|
+
});
|
|
72214
|
+
|
|
72215
|
+
}
|
|
72216
|
+
|
|
72217
|
+
|
|
72076
72218
|
if (roiSet.isUserDefined) {
|
|
72077
72219
|
items.push(
|
|
72078
72220
|
'<hr/>',
|
|
@@ -72081,7 +72223,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
72081
72223
|
click: async () => {
|
|
72082
72224
|
roiSet.removeFeature(feature);
|
|
72083
72225
|
const userDefinedFeatures = await roiSet.getAllFeatures();
|
|
72084
|
-
|
|
72226
|
+
|
|
72085
72227
|
// Delete user defined ROI Set if it is empty
|
|
72086
72228
|
if (Object.keys(userDefinedFeatures).length === 0) {
|
|
72087
72229
|
roiManager.deleteUserDefinedROISet();
|
|
@@ -73254,6 +73396,189 @@ ${indent}columns: ${matrix.columns}
|
|
|
73254
73396
|
|
|
73255
73397
|
}
|
|
73256
73398
|
|
|
73399
|
+
/**
|
|
73400
|
+
* Update deprecated fasta & index urls in the reference object.
|
|
73401
|
+
*/
|
|
73402
|
+
|
|
73403
|
+
const isString = (x) => {
|
|
73404
|
+
return (x && typeof x === "string") || x instanceof String
|
|
73405
|
+
};
|
|
73406
|
+
|
|
73407
|
+
/**
|
|
73408
|
+
* Replaces deprecated s3 fasta URLs with twoBitURLs. The purpose here is to rescue references from saved sessions
|
|
73409
|
+
* that contain pointers to deprectated IGV s3 buckets. These buckets will eventually be deleted
|
|
73410
|
+
*
|
|
73411
|
+
* @param reference
|
|
73412
|
+
*/
|
|
73413
|
+
function updateReference(reference) {
|
|
73414
|
+
|
|
73415
|
+
if (!(requiresUpdate(reference) && updates[reference.id])) {
|
|
73416
|
+
return
|
|
73417
|
+
}
|
|
73418
|
+
|
|
73419
|
+
const updatedReference = updates[reference.id];
|
|
73420
|
+
if (updatedReference) {
|
|
73421
|
+
delete reference.fastaURL;
|
|
73422
|
+
if (reference.indexURL) delete reference.indexURL;
|
|
73423
|
+
reference.twoBitURL = updatedReference.twoBitURL;
|
|
73424
|
+
if (updatedReference.twoBitBptURL) reference.twoBitBptURL = updatedReference.twoBitBptURL;
|
|
73425
|
+
if (updatedReference.chromSizesURL) reference.chromSizesURL = updatedReference.chromSizesURL;
|
|
73426
|
+
}
|
|
73427
|
+
}
|
|
73428
|
+
|
|
73429
|
+
function requiresUpdate(reference) {
|
|
73430
|
+
return isString(reference.fastaURL) &&
|
|
73431
|
+
(reference.fastaURL.startsWith("https://igv.org") ||
|
|
73432
|
+
["igv.org.genomes", "igv.broadinstitute.org", "igv.genepattern.org", "igvdata.broadinstitute.org",
|
|
73433
|
+
"igv-genepattern-org"].some(bucket => reference.fastaURL.includes(bucket)))
|
|
73434
|
+
}
|
|
73435
|
+
|
|
73436
|
+
const updates = {
|
|
73437
|
+
"hs1": {
|
|
73438
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hs1/bigZips/hs1.2bit",
|
|
73439
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hs1/bigZips/hs1.2bit.bpt",
|
|
73440
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hs1/bigZips/hs1.chrom.sizes.txt"
|
|
73441
|
+
},
|
|
73442
|
+
"hg38": {
|
|
73443
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.2bit",
|
|
73444
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.chrom.sizes"
|
|
73445
|
+
},
|
|
73446
|
+
"hg19": {
|
|
73447
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg19/bigZips/hg19.2bit",
|
|
73448
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg19/bigZips/hg19.chrom.sizes"
|
|
73449
|
+
},
|
|
73450
|
+
"hg18": {
|
|
73451
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit",
|
|
73452
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/hg18/bigZips/hg18.chrom.sizes"
|
|
73453
|
+
},
|
|
73454
|
+
"mm39": {
|
|
73455
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm39/bigZips/mm39.2bit",
|
|
73456
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm39/bigZips/mm39.chrom.sizes"
|
|
73457
|
+
},
|
|
73458
|
+
"mm10": {
|
|
73459
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm10/bigZips/mm10.2bit",
|
|
73460
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm10/bigZips/mm10.chrom.sizes"
|
|
73461
|
+
},
|
|
73462
|
+
"mm9": {
|
|
73463
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm9/bigZips/mm9.2bit",
|
|
73464
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/mm9/bigZips/mm9.chrom.sizes"
|
|
73465
|
+
},
|
|
73466
|
+
"rn7": {
|
|
73467
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/015/227/675/GCF_015227675.2/GCF_015227675.2.2bit",
|
|
73468
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/015/227/675/GCF_015227675.2/GCF_015227675.2.2bit.bpt",
|
|
73469
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/015/227/675/GCF_015227675.2/GCF_015227675.2.chrom.sizes.txt"
|
|
73470
|
+
},
|
|
73471
|
+
"rn6": {
|
|
73472
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/001/895/GCF_000001895.5/GCF_000001895.5.2bit",
|
|
73473
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/001/895/GCF_000001895.5/GCF_000001895.5.2bit.bpt",
|
|
73474
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/001/895/GCF_000001895.5/GCF_000001895.5.chrom.sizes.txt"
|
|
73475
|
+
},
|
|
73476
|
+
"gorGor6": {
|
|
73477
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/gorGor6/bigZips/gorGor6.2bit",
|
|
73478
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/gorGor6/bigZips/gorGor6.chrom.sizes"
|
|
73479
|
+
},
|
|
73480
|
+
"gorGor4": {
|
|
73481
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/gorGor4/bigZips/gorGor4.2bit",
|
|
73482
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/gorGor4/bigZips/gorGor4.chrom.sizes"
|
|
73483
|
+
},
|
|
73484
|
+
"panTro6": {
|
|
73485
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro6/bigZips/panTro6.2bit",
|
|
73486
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro6/bigZips/panTro6.chrom.sizes"
|
|
73487
|
+
},
|
|
73488
|
+
"panTro5": {
|
|
73489
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro5/bigZips/panTro5.2bit",
|
|
73490
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro5/bigZips/panTro5.chrom.sizes"
|
|
73491
|
+
},
|
|
73492
|
+
"panTro4": {
|
|
73493
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro4/bigZips/panTro4.2bit",
|
|
73494
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panTro4/bigZips/panTro4.chrom.sizes"
|
|
73495
|
+
},
|
|
73496
|
+
"macFas5": {
|
|
73497
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/macFas5/bigZips/macFas5.2bit",
|
|
73498
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/macFas5/bigZips/macFas5.chrom.sizes"
|
|
73499
|
+
},
|
|
73500
|
+
"panPan2": {
|
|
73501
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panPan2/bigZips/panPan2.2bit",
|
|
73502
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/panPan2/bigZips/panPan2.chrom.sizes"
|
|
73503
|
+
},
|
|
73504
|
+
"canFam6": {
|
|
73505
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam6/bigZips/canFam6.2bit",
|
|
73506
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam6/bigZips/canFam6.chrom.sizes"
|
|
73507
|
+
},
|
|
73508
|
+
"canFam5": {
|
|
73509
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam5/bigZips/canFam5.2bit",
|
|
73510
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam5/bigZips/canFam5.chrom.sizes"
|
|
73511
|
+
},
|
|
73512
|
+
"canFam4": {
|
|
73513
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.2bit",
|
|
73514
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.chrom.sizes"
|
|
73515
|
+
},
|
|
73516
|
+
"canFam3": {
|
|
73517
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam3/bigZips/canFam3.2bit",
|
|
73518
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam3/bigZips/canFam3.chrom.sizes"
|
|
73519
|
+
},
|
|
73520
|
+
"bosTau9": {
|
|
73521
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/bosTau9/bigZips/bosTau9.2bit",
|
|
73522
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/bosTau9/bigZips/bosTau9.chrom.sizes"
|
|
73523
|
+
},
|
|
73524
|
+
"bosTau8": {
|
|
73525
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/bosTau8/bigZips/bosTau8.2bit",
|
|
73526
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/bosTau8/bigZips/bosTau8.chrom.sizes"
|
|
73527
|
+
},
|
|
73528
|
+
"susScr11": {
|
|
73529
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/susScr11/bigZips/susScr11.2bit",
|
|
73530
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/susScr11/bigZips/susScr11.chrom.sizes"
|
|
73531
|
+
},
|
|
73532
|
+
"galGal6": {
|
|
73533
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/galGal6/bigZips/galGal6.2bit",
|
|
73534
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/galGal6/bigZips/galGal6.chrom.sizes"
|
|
73535
|
+
},
|
|
73536
|
+
"danRer11": {
|
|
73537
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/danRer11/bigZips/danRer11.2bit",
|
|
73538
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/danRer11/bigZips/danRer11.chrom.sizes"
|
|
73539
|
+
},
|
|
73540
|
+
"danRer10": {
|
|
73541
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/danRer10/bigZips/danRer10.2bit",
|
|
73542
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/danRer10/bigZips/danRer10.chrom.sizes"
|
|
73543
|
+
},
|
|
73544
|
+
"ce11": {
|
|
73545
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/ce11/bigZips/ce11.2bit",
|
|
73546
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/ce11/bigZips/ce11.chrom.sizes"
|
|
73547
|
+
},
|
|
73548
|
+
"dm6": {
|
|
73549
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/dm6/bigZips/dm6.2bit",
|
|
73550
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/dm6/bigZips/dm6.chrom.sizes"
|
|
73551
|
+
},
|
|
73552
|
+
"dm3": {
|
|
73553
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/goldenPath/dm3/bigZips/dm3.2bit",
|
|
73554
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/goldenPath/dm3/bigZips/dm3.chrom.sizes"
|
|
73555
|
+
},
|
|
73556
|
+
"sacCer3": {
|
|
73557
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/146/045/GCF_000146045.2/GCF_000146045.2.2bit",
|
|
73558
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/146/045/GCF_000146045.2/GCF_000146045.2.2bit.bpt",
|
|
73559
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/146/045/GCF_000146045.2/GCF_000146045.2.chrom.sizes.txt"
|
|
73560
|
+
},
|
|
73561
|
+
"GCF_000002945.1": {
|
|
73562
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/002/945/GCF_000002945.1/GCF_000002945.1.2bit",
|
|
73563
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/002/945/GCF_000002945.1/GCF_000002945.1.2bit.bpt",
|
|
73564
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/002/945/GCF_000002945.1/GCF_000002945.1.chrom.sizes.txt"
|
|
73565
|
+
},
|
|
73566
|
+
"GCF_009858895.2": {
|
|
73567
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/009/858/895/GCF_009858895.2/GCF_009858895.2.2bit",
|
|
73568
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/009/858/895/GCF_009858895.2/GCF_009858895.2.2bit.bpt",
|
|
73569
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/009/858/895/GCF_009858895.2/GCF_009858895.2.chrom.sizes.txt"
|
|
73570
|
+
},
|
|
73571
|
+
"tair10": {
|
|
73572
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/001/735/GCF_000001735.3/GCF_000001735.3.2bit",
|
|
73573
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/001/735/GCF_000001735.3/GCF_000001735.3.chrom.sizes.txt"
|
|
73574
|
+
},
|
|
73575
|
+
"GCA_000022165.1": {
|
|
73576
|
+
"twoBitURL": "https://hgdownload.soe.ucsc.edu/hubs/GCA/000/022/165/GCA_000022165.1/GCA_000022165.1.2bit",
|
|
73577
|
+
"twoBitBptURL": "https://hgdownload.soe.ucsc.edu/hubs/GCA/000/022/165/GCA_000022165.1/GCA_000022165.1.2bit.bpt",
|
|
73578
|
+
"chromSizesURL": "https://hgdownload.soe.ucsc.edu/hubs/GCA/000/022/165/GCA_000022165.1/GCA_000022165.1.chrom.sizes.txt"
|
|
73579
|
+
}
|
|
73580
|
+
};
|
|
73581
|
+
|
|
73257
73582
|
const ucsdIDMap = new Map([
|
|
73258
73583
|
["1kg_ref", "hg18"],
|
|
73259
73584
|
["1kg_v37", "hg19"],
|
|
@@ -73275,6 +73600,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
73275
73600
|
|
|
73276
73601
|
static async createGenome(options, browser) {
|
|
73277
73602
|
|
|
73603
|
+
updateReference(options);
|
|
73278
73604
|
const genome = new Genome(options, browser);
|
|
73279
73605
|
await genome.init();
|
|
73280
73606
|
return genome
|
|
@@ -73298,7 +73624,6 @@ ${indent}columns: ${matrix.columns}
|
|
|
73298
73624
|
// Load sequence
|
|
73299
73625
|
this.sequence = await loadSequence(config, this.browser);
|
|
73300
73626
|
|
|
73301
|
-
|
|
73302
73627
|
// Load cytobands. This is optional but required to support the ideogram. Only needed for whole genome view
|
|
73303
73628
|
if(false !== config.showIdeogram && false !== config.wholeGenomeView) {
|
|
73304
73629
|
if (config.cytobandURL) {
|
|
@@ -73342,10 +73667,14 @@ ${indent}columns: ${matrix.columns}
|
|
|
73342
73667
|
} else {
|
|
73343
73668
|
this.#wgChromosomeNames = config.chromosomeOrder.split(',').map(nm => nm.trim());
|
|
73344
73669
|
}
|
|
73670
|
+
// Trim to remove non-existent chromosomes
|
|
73671
|
+
await this.chromAlias.preload(this.#wgChromosomeNames);
|
|
73672
|
+
this.#wgChromosomeNames =
|
|
73673
|
+
this.#wgChromosomeNames.map(c => this.getChromosomeName(c)).filter(c => this.chromosomes.has(c));
|
|
73345
73674
|
} else {
|
|
73346
73675
|
this.#wgChromosomeNames = trimSmallChromosomes(this.chromosomes);
|
|
73676
|
+
await this.chromAlias.preload(this.#wgChromosomeNames);
|
|
73347
73677
|
}
|
|
73348
|
-
await this.chromAlias.preload(this.#wgChromosomeNames);
|
|
73349
73678
|
}
|
|
73350
73679
|
|
|
73351
73680
|
// Optionally create the psuedo chromosome "all" to support whole genome view
|
|
@@ -73618,7 +73947,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
73618
73947
|
function generateGenomeID(config) {
|
|
73619
73948
|
if (config.id !== undefined) {
|
|
73620
73949
|
return config.id
|
|
73621
|
-
} else if (config.fastaURL && isString$
|
|
73950
|
+
} else if (config.fastaURL && isString$3(config.fastaURL) && !config.fastaURL.startsWith("data:")) {
|
|
73622
73951
|
return config.fastaURL
|
|
73623
73952
|
} else if (config.fastaURL && config.fastaURL.name) {
|
|
73624
73953
|
return config.fastaURL.name
|
|
@@ -74351,7 +74680,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74351
74680
|
const urlOrFile = options.url || options.file;
|
|
74352
74681
|
|
|
74353
74682
|
let config;
|
|
74354
|
-
if (options.url && isString$
|
|
74683
|
+
if (options.url && isString$3(options.url) && (options.url.startsWith("blob:") || options.url.startsWith("data:"))) {
|
|
74355
74684
|
const json = Browser.uncompressSession(options.url);
|
|
74356
74685
|
config = JSON.parse(json);
|
|
74357
74686
|
} else {
|
|
@@ -74430,7 +74759,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74430
74759
|
return
|
|
74431
74760
|
}
|
|
74432
74761
|
|
|
74433
|
-
const genomeConfig = isString$
|
|
74762
|
+
const genomeConfig = isString$3(genomeOrReference) ?
|
|
74434
74763
|
await GenomeUtils.expandReference(this.alert, genomeOrReference) :
|
|
74435
74764
|
genomeOrReference;
|
|
74436
74765
|
|
|
@@ -74552,7 +74881,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74552
74881
|
}
|
|
74553
74882
|
|
|
74554
74883
|
/**
|
|
74555
|
-
* Load a reference genome object. This includes the
|
|
74884
|
+
* Load a reference genome object. This includes the sequence, and optional cytoband, but no tracks. This method
|
|
74556
74885
|
* is used by loadGenome and loadSession.
|
|
74557
74886
|
*
|
|
74558
74887
|
* @param genomeConfig
|
|
@@ -74585,7 +74914,10 @@ ${indent}columns: ${matrix.columns}
|
|
|
74585
74914
|
|
|
74586
74915
|
const locusFound = await this.search(locus, true);
|
|
74587
74916
|
if (!locusFound) {
|
|
74588
|
-
|
|
74917
|
+
console.error(`Cannot set initial locus ${locus}`);
|
|
74918
|
+
if(locus !== genome.initialLocus) {
|
|
74919
|
+
await this.search(genome.initialLocus);
|
|
74920
|
+
}
|
|
74589
74921
|
}
|
|
74590
74922
|
|
|
74591
74923
|
if (genomeChange) {
|
|
@@ -74617,7 +74949,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74617
74949
|
|
|
74618
74950
|
// Translate the generic "url" field, used by clients such as igv-webapp
|
|
74619
74951
|
if (idOrConfig.url) {
|
|
74620
|
-
if (isString$
|
|
74952
|
+
if (isString$3(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt")) {
|
|
74621
74953
|
idOrConfig.hubURL = idOrConfig.url;
|
|
74622
74954
|
delete idOrConfig.url;
|
|
74623
74955
|
} else if ("gbk" === getFileExtension(idOrConfig.url)) {
|
|
@@ -74627,11 +74959,11 @@ ${indent}columns: ${matrix.columns}
|
|
|
74627
74959
|
}
|
|
74628
74960
|
|
|
74629
74961
|
let genomeConfig;
|
|
74630
|
-
const isHubGenome = idOrConfig.hubURL || (idOrConfig.url && isString$
|
|
74962
|
+
const isHubGenome = idOrConfig.hubURL || (idOrConfig.url && isString$3(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt"));
|
|
74631
74963
|
if (isHubGenome) {
|
|
74632
74964
|
const hub = await loadHub(idOrConfig.hubURL || idOrConfig.url);
|
|
74633
74965
|
genomeConfig = hub.getGenomeConfig();
|
|
74634
|
-
} else if (isString$
|
|
74966
|
+
} else if (isString$3(idOrConfig) || !(idOrConfig.url || idOrConfig.fastaURL || idOrConfig.twoBitURL || idOrConfig.gbkURL)) {
|
|
74635
74967
|
// Either an ID, a json string, or an object missing required properties.
|
|
74636
74968
|
genomeConfig = await GenomeUtils.expandReference(this.alert, idOrConfig);
|
|
74637
74969
|
} else {
|
|
@@ -74798,7 +75130,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74798
75130
|
async #loadTrackHelper(config) {
|
|
74799
75131
|
|
|
74800
75132
|
// config might be json
|
|
74801
|
-
if (isString$
|
|
75133
|
+
if (isString$3(config)) {
|
|
74802
75134
|
config = JSON.parse(config);
|
|
74803
75135
|
}
|
|
74804
75136
|
|
|
@@ -74928,7 +75260,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74928
75260
|
|
|
74929
75261
|
// Resolve function and promise urls
|
|
74930
75262
|
let url = await resolveURL(config.url || config.fastaURL);
|
|
74931
|
-
if (isString$
|
|
75263
|
+
if (isString$3(url)) {
|
|
74932
75264
|
url = url.trim();
|
|
74933
75265
|
}
|
|
74934
75266
|
|
|
@@ -74976,7 +75308,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74976
75308
|
const featureSource = FeatureSource(config, this.genome);
|
|
74977
75309
|
config._featureSource = featureSource; // This is a temp variable, bit of a hack
|
|
74978
75310
|
const trackType = await featureSource.trackType();
|
|
74979
|
-
if (trackType) {
|
|
75311
|
+
if (trackType && knownTrackTypes().has(trackType)) {
|
|
74980
75312
|
type = trackType;
|
|
74981
75313
|
} else {
|
|
74982
75314
|
type = "annotation";
|