igv 2.10.5 → 2.11.2
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 -23
- package/dist/igv.esm.js +1712 -1052
- package/dist/igv.esm.min.js +6 -6
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +2066 -1342
- package/dist/igv.min.js +7 -7
- package/dist/igv.min.js.map +1 -1
- package/package.json +11 -9
package/dist/igv.esm.js
CHANGED
|
@@ -8167,7 +8167,7 @@ function applyStyle$1(elem, style) {
|
|
|
8167
8167
|
}
|
|
8168
8168
|
}
|
|
8169
8169
|
|
|
8170
|
-
function guid$
|
|
8170
|
+
function guid$2 () {
|
|
8171
8171
|
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4);
|
|
8172
8172
|
}
|
|
8173
8173
|
|
|
@@ -8760,8 +8760,8 @@ async function resolveURL(url) {
|
|
|
8760
8760
|
|
|
8761
8761
|
function getFilename$1(urlOrFile) {
|
|
8762
8762
|
|
|
8763
|
-
if (
|
|
8764
|
-
return urlOrFile.name
|
|
8763
|
+
if (urlOrFile.name !== undefined) {
|
|
8764
|
+
return urlOrFile.name
|
|
8765
8765
|
} else if (isString$3(urlOrFile)) {
|
|
8766
8766
|
|
|
8767
8767
|
let index = urlOrFile.lastIndexOf("/");
|
|
@@ -8772,21 +8772,24 @@ function getFilename$1(urlOrFile) {
|
|
|
8772
8772
|
if (index > 0) {
|
|
8773
8773
|
filename = filename.substr(0, index);
|
|
8774
8774
|
}
|
|
8775
|
-
return filename
|
|
8775
|
+
return filename
|
|
8776
8776
|
} else {
|
|
8777
|
-
throw Error(`Expected File or string, got ${typeof urlOrFile}`)
|
|
8777
|
+
throw Error(`Expected File or string, got ${typeof urlOrFile}`)
|
|
8778
8778
|
}
|
|
8779
8779
|
}
|
|
8780
8780
|
|
|
8781
8781
|
/**
|
|
8782
|
-
* Test if object is a File or File-like object
|
|
8783
|
-
* but the purpose is to distinguish the object from url strings
|
|
8782
|
+
* Test if object is a File or File-like object.
|
|
8784
8783
|
*
|
|
8785
8784
|
* @param object
|
|
8786
8785
|
*/
|
|
8787
8786
|
function isFile(object) {
|
|
8788
|
-
|
|
8789
|
-
|
|
8787
|
+
if(!object) {
|
|
8788
|
+
return false;
|
|
8789
|
+
}
|
|
8790
|
+
return typeof object !== 'function' &&
|
|
8791
|
+
(object instanceof File ||
|
|
8792
|
+
(object.hasOwnProperty("name") && typeof object.slice === 'function' && typeof object.arrayBuffer === 'function'))
|
|
8790
8793
|
}
|
|
8791
8794
|
|
|
8792
8795
|
const isFilePath = isFile; // deprecated
|
|
@@ -17121,7 +17124,6 @@ function getOauthToken(url) {
|
|
|
17121
17124
|
* @returns the oauth token
|
|
17122
17125
|
*/
|
|
17123
17126
|
async function fetchGoogleAccessToken(url) {
|
|
17124
|
-
console.log("Fetch token for " + url);
|
|
17125
17127
|
if (isInitialized()) {
|
|
17126
17128
|
const scope = getScopeForURL(url);
|
|
17127
17129
|
const googleToken = await getAccessToken(scope);
|
|
@@ -18564,11 +18566,11 @@ class AlertDialog {
|
|
|
18564
18566
|
this.errorHeadline.textContent = '';
|
|
18565
18567
|
|
|
18566
18568
|
// body container
|
|
18567
|
-
let bodyContainer = div({
|
|
18569
|
+
let bodyContainer = div({class: 'igv-ui-alert-dialog-body'});
|
|
18568
18570
|
this.container.appendChild(bodyContainer);
|
|
18569
18571
|
|
|
18570
18572
|
// body copy
|
|
18571
|
-
this.body = div({
|
|
18573
|
+
this.body = div({class: 'igv-ui-alert-dialog-body-copy'});
|
|
18572
18574
|
bodyContainer.appendChild(this.body);
|
|
18573
18575
|
|
|
18574
18576
|
// ok container
|
|
@@ -19089,7 +19091,7 @@ function createMenuElements$1(itemList, popover) {
|
|
|
19089
19091
|
|
|
19090
19092
|
function embedCSS$2() {
|
|
19091
19093
|
|
|
19092
|
-
var css = '.igv-ui-popover {\n cursor: default;\n position: absolute;\n z-index: 2048;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n background-color: white; }\n .igv-ui-popover > div:first-child {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-popover > div:first-child > div:first-child {\n margin-left: 4px; }\n .igv-ui-popover > div:first-child > div:last-child {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-popover > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-popover > div:last-child {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: 400px;\n max-width: 800px;\n background-color: white; }\n .igv-ui-popover > div:last-child > div {\n -webkit-user-select: all;\n /* Chrome/Safari */\n -moz-user-select: all;\n /* Firefox */\n margin-left: 4px;\n margin-right: 4px;\n min-width: 220px;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n .igv-ui-popover > div:last-child > div > span {\n font-weight: bolder; }\n .igv-ui-popover > div:last-child hr {\n width: 100%; }\n\n.igv-ui-alert-dialog-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n top: 50%;\n left: 50%;\n width: 400px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n outline: none;\n font-family: \"Open Sans\", sans-serif;\n font-size: 15px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:first-child {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-alert-dialog-container > div:first-child div:first-child {\n padding-left: 8px; }\n .igv-ui-alert-dialog-container #igv-ui-alert-dialog-body {\n color: #373737;\n width: 100%;\n height: calc(100% - 24px - 64px);\n overflow-y: scroll; }\n .igv-ui-alert-dialog-container #igv-ui-alert-dialog-body #igv-ui-alert-dialog-body-copy {\n cursor: pointer;\n margin: 16px;\n width: auto;\n height: auto;\n overflow-wrap: break-word;\n word-break: break-word;\n background-color: white;\n border: unset; }\n .igv-ui-alert-dialog-container > div:last-child {\n width: 100%;\n margin-bottom: 10px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:last-child div {\n margin: unset;\n width: 40px;\n height: 30px;\n line-height: 30px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n border-color: #2B81AF;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-alert-dialog-container > div:last-child div:hover {\n cursor: pointer;\n border-color: #25597f;\n background-color: #25597f; }\n\n.igv-ui-color-swatch {\n position: relative;\n box-sizing: content-box;\n display: flex;\n flex-flow: row;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n width: 32px;\n height: 32px;\n border-style: solid;\n border-width: 2px;\n border-color: white;\n border-radius: 4px; }\n\n.igv-ui-color-swatch:hover {\n border-color: dimgray; }\n\n.igv-ui-colorpicker-menu-close-button {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 32px;\n margin-top: 4px;\n margin-bottom: 4px;\n padding-right: 8px; }\n .igv-ui-colorpicker-menu-close-button i.fa {\n display: block;\n margin-left: 4px;\n margin-right: 4px;\n color: #5f5f5f; }\n .igv-ui-colorpicker-menu-close-button i.fa:hover,\n .igv-ui-colorpicker-menu-close-button i.fa:focus,\n .igv-ui-colorpicker-menu-close-button i.fa:active {\n cursor: pointer;\n color: #0f0f0f; }\n\n.igv-ui-generic-dialog-container {\n box-sizing: content-box;\n position: fixed;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-generic-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd; }\n .igv-ui-generic-container div:first-child div {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px; }\n\n.igv-ui-dialog {\n z-index: 2048;\n position: fixed;\n width: fit-content;\n height: fit-content;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n background-color: white;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400; }\n .igv-ui-dialog .igv-ui-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-dialog .igv-ui-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-dialog .igv-ui-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-dialog .igv-ui-dialog-one-liner {\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin: 8px;\n overflow-wrap: break-word;\n background-color: white;\n font-weight: bold; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel {\n width: 100%;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div {\n margin: 16px;\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child {\n background-color: #5ea4e0; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child {\n background-color: #c4c4c4; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-dialog .igv-ui-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-dialog .igv-ui-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-panel, .igv-ui-panel-column, .igv-ui-panel-row {\n z-index: 2048;\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n.igv-ui-panel-column {\n display: flex;\n flex-direction: column; }\n\n.igv-ui-panel-row {\n display: flex;\n flex-direction: row; }\n\n.igv-ui-textbox {\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n/*# sourceMappingURL=igv-ui.css.map */\n';
|
|
19094
|
+
var css = '.igv-ui-popover {\n cursor: default;\n position: absolute;\n z-index: 2048;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n background-color: white; }\n .igv-ui-popover > div:first-child {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-popover > div:first-child > div:first-child {\n margin-left: 4px; }\n .igv-ui-popover > div:first-child > div:last-child {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-popover > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-popover > div:last-child {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: 400px;\n max-width: 800px;\n background-color: white; }\n .igv-ui-popover > div:last-child > div {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n margin-left: 4px;\n margin-right: 4px;\n min-width: 220px;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n .igv-ui-popover > div:last-child > div > span {\n font-weight: bolder; }\n .igv-ui-popover > div:last-child hr {\n width: 100%; }\n\n.igv-ui-alert-dialog-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n top: 50%;\n left: 50%;\n width: 400px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n outline: none;\n font-family: \"Open Sans\", sans-serif;\n font-size: 15px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:first-child {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-alert-dialog-container > div:first-child div:first-child {\n padding-left: 8px; }\n .igv-ui-alert-dialog-container .igv-ui-alert-dialog-body {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n color: #373737;\n width: 100%;\n height: calc(100% - 24px - 64px);\n overflow-y: scroll; }\n .igv-ui-alert-dialog-container .igv-ui-alert-dialog-body .igv-ui-alert-dialog-body-copy {\n margin: 16px;\n width: auto;\n height: auto;\n overflow-wrap: break-word;\n word-break: break-word;\n background-color: white;\n border: unset; }\n .igv-ui-alert-dialog-container > div:last-child {\n width: 100%;\n margin-bottom: 10px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:last-child div {\n margin: unset;\n width: 40px;\n height: 30px;\n line-height: 30px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n border-color: #2B81AF;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-alert-dialog-container > div:last-child div:hover {\n cursor: pointer;\n border-color: #25597f;\n background-color: #25597f; }\n\n.igv-ui-color-swatch {\n position: relative;\n box-sizing: content-box;\n display: flex;\n flex-flow: row;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n width: 32px;\n height: 32px;\n border-style: solid;\n border-width: 2px;\n border-color: white;\n border-radius: 4px; }\n\n.igv-ui-color-swatch:hover {\n border-color: dimgray; }\n\n.igv-ui-colorpicker-menu-close-button {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 32px;\n margin-top: 4px;\n margin-bottom: 4px;\n padding-right: 8px; }\n .igv-ui-colorpicker-menu-close-button i.fa {\n display: block;\n margin-left: 4px;\n margin-right: 4px;\n color: #5f5f5f; }\n .igv-ui-colorpicker-menu-close-button i.fa:hover,\n .igv-ui-colorpicker-menu-close-button i.fa:focus,\n .igv-ui-colorpicker-menu-close-button i.fa:active {\n cursor: pointer;\n color: #0f0f0f; }\n\n.igv-ui-generic-dialog-container {\n box-sizing: content-box;\n position: fixed;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-generic-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-container > div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd; }\n .igv-ui-generic-container > div:first-child > div {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px; }\n\n.igv-ui-dialog {\n z-index: 2048;\n position: fixed;\n width: fit-content;\n height: fit-content;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n background-color: white;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400; }\n .igv-ui-dialog .igv-ui-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-dialog .igv-ui-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-dialog .igv-ui-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-dialog .igv-ui-dialog-one-liner {\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin: 8px;\n overflow-wrap: break-word;\n background-color: white;\n font-weight: bold; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel {\n width: 100%;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div {\n margin: 16px;\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child {\n background-color: #5ea4e0; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child {\n background-color: #c4c4c4; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-dialog .igv-ui-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-dialog .igv-ui-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-panel, .igv-ui-panel-column, .igv-ui-panel-row {\n z-index: 2048;\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n.igv-ui-panel-column {\n display: flex;\n flex-direction: column; }\n\n.igv-ui-panel-row {\n display: flex;\n flex-direction: row; }\n\n.igv-ui-textbox {\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n/*# sourceMappingURL=igv-ui.css.map */\n';
|
|
19093
19095
|
|
|
19094
19096
|
var style = document.createElement('style');
|
|
19095
19097
|
style.setAttribute('type', 'text/css');
|
|
@@ -19709,6 +19711,7 @@ const knownFileExtensions = new Set([
|
|
|
19709
19711
|
"vcf",
|
|
19710
19712
|
"bb",
|
|
19711
19713
|
"bigbed",
|
|
19714
|
+
"biginteract",
|
|
19712
19715
|
"bw",
|
|
19713
19716
|
"bigwig",
|
|
19714
19717
|
"bam",
|
|
@@ -19859,6 +19862,7 @@ function inferTrackType(config) {
|
|
|
19859
19862
|
case "bed":
|
|
19860
19863
|
case "bigbed":
|
|
19861
19864
|
case "bb":
|
|
19865
|
+
case "biginteract":
|
|
19862
19866
|
return "bedtype"
|
|
19863
19867
|
default:
|
|
19864
19868
|
return "annotation"
|
|
@@ -19897,6 +19901,218 @@ function translateDeprecatedTypes(config) {
|
|
|
19897
19901
|
}
|
|
19898
19902
|
}
|
|
19899
19903
|
|
|
19904
|
+
/*
|
|
19905
|
+
* The MIT License (MIT)
|
|
19906
|
+
*
|
|
19907
|
+
* Copyright (c) 2014 Broad Institute
|
|
19908
|
+
*
|
|
19909
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19910
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
19911
|
+
* in the Software without restriction, including without limitation the rights
|
|
19912
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19913
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19914
|
+
* furnished to do so, subject to the following conditions:
|
|
19915
|
+
*
|
|
19916
|
+
* The above copyright notice and this permission notice shall be included in
|
|
19917
|
+
* all copies or substantial portions of the Software.
|
|
19918
|
+
*
|
|
19919
|
+
*
|
|
19920
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19921
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19922
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19923
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19924
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19925
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19926
|
+
* THE SOFTWARE.
|
|
19927
|
+
*/
|
|
19928
|
+
|
|
19929
|
+
/**
|
|
19930
|
+
* Test if the given value is a string or number. Not using typeof as it fails on boxed primitives.
|
|
19931
|
+
*
|
|
19932
|
+
* @param value
|
|
19933
|
+
* @returns boolean
|
|
19934
|
+
*/
|
|
19935
|
+
|
|
19936
|
+
function isSimpleType(value) {
|
|
19937
|
+
const simpleTypes = new Set(["boolean", "number", "string", "symbol"]);
|
|
19938
|
+
const valueType = typeof value;
|
|
19939
|
+
return (value !== undefined && (simpleTypes.has(valueType) || value.substring || value.toFixed))
|
|
19940
|
+
}
|
|
19941
|
+
|
|
19942
|
+
function buildOptions(config, options) {
|
|
19943
|
+
|
|
19944
|
+
var defaultOptions = {
|
|
19945
|
+
oauthToken: config.oauthToken,
|
|
19946
|
+
headers: config.headers,
|
|
19947
|
+
withCredentials: config.withCredentials,
|
|
19948
|
+
filename: config.filename
|
|
19949
|
+
};
|
|
19950
|
+
|
|
19951
|
+
return Object.assign(defaultOptions, options)
|
|
19952
|
+
}
|
|
19953
|
+
|
|
19954
|
+
/**
|
|
19955
|
+
* isMobile test from http://detectmobilebrowsers.com
|
|
19956
|
+
* TODO -- improve UI design so this isn't neccessary
|
|
19957
|
+
* @returns {boolean}
|
|
19958
|
+
*/
|
|
19959
|
+
|
|
19960
|
+
// igv.isMobile = function () {
|
|
19961
|
+
//
|
|
19962
|
+
// const a = (navigator.userAgent || navigator.vendor || window.opera);
|
|
19963
|
+
// return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) ||
|
|
19964
|
+
// /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4)))
|
|
19965
|
+
//
|
|
19966
|
+
// }
|
|
19967
|
+
|
|
19968
|
+
const doAutoscale = function (features) {
|
|
19969
|
+
var min, max;
|
|
19970
|
+
|
|
19971
|
+
if (features.length > 0) {
|
|
19972
|
+
min = Number.MAX_VALUE;
|
|
19973
|
+
max = -Number.MAX_VALUE;
|
|
19974
|
+
|
|
19975
|
+
features.forEach(function (f) {
|
|
19976
|
+
if (!Number.isNaN(f.value)) {
|
|
19977
|
+
min = Math.min(min, f.value);
|
|
19978
|
+
max = Math.max(max, f.value);
|
|
19979
|
+
}
|
|
19980
|
+
});
|
|
19981
|
+
|
|
19982
|
+
// Insure we have a zero baseline
|
|
19983
|
+
if (max > 0) min = Math.min(0, min);
|
|
19984
|
+
if (max < 0) max = 0;
|
|
19985
|
+
} else {
|
|
19986
|
+
// No features -- default
|
|
19987
|
+
min = 0;
|
|
19988
|
+
max = 100;
|
|
19989
|
+
}
|
|
19990
|
+
|
|
19991
|
+
return {min: min, max: max}
|
|
19992
|
+
};
|
|
19993
|
+
|
|
19994
|
+
const validateLocusExtent = function (chromosomeLengthBP, extent, minimumBP) {
|
|
19995
|
+
|
|
19996
|
+
let ss = extent.start;
|
|
19997
|
+
let ee = extent.end;
|
|
19998
|
+
|
|
19999
|
+
if (undefined === ee) {
|
|
20000
|
+
|
|
20001
|
+
ss -= minimumBP / 2;
|
|
20002
|
+
ee = ss + minimumBP;
|
|
20003
|
+
|
|
20004
|
+
if (ee > chromosomeLengthBP) {
|
|
20005
|
+
ee = chromosomeLengthBP;
|
|
20006
|
+
ss = ee - minimumBP;
|
|
20007
|
+
} else if (ss < 0) {
|
|
20008
|
+
ss = 0;
|
|
20009
|
+
ee = minimumBP;
|
|
20010
|
+
}
|
|
20011
|
+
|
|
20012
|
+
} else if (ee - ss < minimumBP) {
|
|
20013
|
+
|
|
20014
|
+
const center = (ee + ss) / 2;
|
|
20015
|
+
|
|
20016
|
+
if (center - minimumBP / 2 < 0) {
|
|
20017
|
+
ss = 0;
|
|
20018
|
+
ee = ss + minimumBP;
|
|
20019
|
+
} else if (center + minimumBP / 2 > chromosomeLengthBP) {
|
|
20020
|
+
ee = chromosomeLengthBP;
|
|
20021
|
+
ss = ee - minimumBP;
|
|
20022
|
+
} else {
|
|
20023
|
+
ss = center - minimumBP / 2;
|
|
20024
|
+
ee = ss + minimumBP;
|
|
20025
|
+
}
|
|
20026
|
+
}
|
|
20027
|
+
|
|
20028
|
+
extent.start = Math.ceil(ss);
|
|
20029
|
+
extent.end = Math.floor(ee);
|
|
20030
|
+
};
|
|
20031
|
+
|
|
20032
|
+
/*!
|
|
20033
|
+
* is-number <https://github.com/jonschlinkert/is-number>
|
|
20034
|
+
*
|
|
20035
|
+
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
20036
|
+
* Released under the MIT License.
|
|
20037
|
+
*/
|
|
20038
|
+
|
|
20039
|
+
const isNumber = function (num) {
|
|
20040
|
+
if (typeof num === 'number') {
|
|
20041
|
+
return num - num === 0
|
|
20042
|
+
}
|
|
20043
|
+
if (typeof num === 'string' && num.trim() !== '') {
|
|
20044
|
+
return Number.isFinite ? Number.isFinite(+num) : isFinite(+num)
|
|
20045
|
+
}
|
|
20046
|
+
return false
|
|
20047
|
+
};
|
|
20048
|
+
|
|
20049
|
+
async function getFilename(url) {
|
|
20050
|
+
if (isString$3(url) && url.startsWith("https://drive.google.com")) {
|
|
20051
|
+
// This will fail if Google API key is not defined
|
|
20052
|
+
if (getApiKey() === undefined) {
|
|
20053
|
+
throw Error("Google drive is referenced, but API key is not defined. An API key is required for Google Drive access")
|
|
20054
|
+
}
|
|
20055
|
+
const json = await getDriveFileInfo(url);
|
|
20056
|
+
return json.originalFileName || json.name
|
|
20057
|
+
} else {
|
|
20058
|
+
return getFilename$1(url)
|
|
20059
|
+
}
|
|
20060
|
+
}
|
|
20061
|
+
|
|
20062
|
+
function prettyBasePairNumber(raw) {
|
|
20063
|
+
|
|
20064
|
+
var denom,
|
|
20065
|
+
units,
|
|
20066
|
+
value,
|
|
20067
|
+
floored;
|
|
20068
|
+
|
|
20069
|
+
if (raw > 1e7) {
|
|
20070
|
+
denom = 1e6;
|
|
20071
|
+
units = " mb";
|
|
20072
|
+
} else if (raw > 1e4) {
|
|
20073
|
+
|
|
20074
|
+
denom = 1e3;
|
|
20075
|
+
units = " kb";
|
|
20076
|
+
|
|
20077
|
+
value = raw / denom;
|
|
20078
|
+
floored = Math.floor(value);
|
|
20079
|
+
return numberFormatter$1(floored) + units
|
|
20080
|
+
} else {
|
|
20081
|
+
return numberFormatter$1(raw) + " bp"
|
|
20082
|
+
}
|
|
20083
|
+
|
|
20084
|
+
value = raw / denom;
|
|
20085
|
+
floored = Math.floor(value);
|
|
20086
|
+
|
|
20087
|
+
return floored.toString() + units
|
|
20088
|
+
}
|
|
20089
|
+
|
|
20090
|
+
|
|
20091
|
+
function isDataURL(obj) {
|
|
20092
|
+
return (isString$3(obj) && obj.startsWith("data:"))
|
|
20093
|
+
}
|
|
20094
|
+
|
|
20095
|
+
function createColumn(columnContainer, className) {
|
|
20096
|
+
const column = div$1({class: className});
|
|
20097
|
+
columnContainer.appendChild(column);
|
|
20098
|
+
}
|
|
20099
|
+
|
|
20100
|
+
|
|
20101
|
+
function insertElementBefore(element, referenceNode) {
|
|
20102
|
+
referenceNode.parentNode.insertBefore(element, referenceNode);
|
|
20103
|
+
}
|
|
20104
|
+
|
|
20105
|
+
function insertElementAfter(element, referenceNode) {
|
|
20106
|
+
referenceNode.parentNode.insertBefore(element, referenceNode.nextSibling);
|
|
20107
|
+
}
|
|
20108
|
+
|
|
20109
|
+
/**
|
|
20110
|
+
* Test to see if page is loaded in a secure context, that is by https or is localhost.
|
|
20111
|
+
*/
|
|
20112
|
+
function isSecureContext() {
|
|
20113
|
+
return window.location.protocol === "https:" || window.location.hostname === "localhost"
|
|
20114
|
+
}
|
|
20115
|
+
|
|
19900
20116
|
/*
|
|
19901
20117
|
* The MIT License (MIT)
|
|
19902
20118
|
*
|
|
@@ -20275,7 +20491,7 @@ class Viewport {
|
|
|
20275
20491
|
|
|
20276
20492
|
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
20277
20493
|
|
|
20278
|
-
this.guid = guid$
|
|
20494
|
+
this.guid = guid$2();
|
|
20279
20495
|
this.trackView = trackView;
|
|
20280
20496
|
this.referenceFrame = referenceFrame;
|
|
20281
20497
|
|
|
@@ -22054,7 +22270,7 @@ GenomicInterval.prototype.containsRange = function (range) {
|
|
|
22054
22270
|
|
|
22055
22271
|
const splitLines$3 = splitLines$5;
|
|
22056
22272
|
|
|
22057
|
-
const reservedProperties = new Set(['fastaURL', 'indexURL', 'cytobandURL', 'indexed']);
|
|
22273
|
+
const reservedProperties = new Set(['fastaURL', 'indexURL', 'compressedIndexURL', 'cytobandURL', 'indexed']);
|
|
22058
22274
|
|
|
22059
22275
|
class FastaSequence {
|
|
22060
22276
|
|
|
@@ -22062,6 +22278,7 @@ class FastaSequence {
|
|
|
22062
22278
|
|
|
22063
22279
|
this.file = reference.fastaURL;
|
|
22064
22280
|
this.indexFile = reference.indexURL || reference.indexFile || this.file + ".fai";
|
|
22281
|
+
this.compressedIndexFile = reference.compressedIndexURL || false;
|
|
22065
22282
|
this.withCredentials = reference.withCredentials;
|
|
22066
22283
|
this.chromosomeNames = [];
|
|
22067
22284
|
this.chromosomes = {};
|
|
@@ -22147,77 +22364,292 @@ class FastaSequence {
|
|
|
22147
22364
|
}
|
|
22148
22365
|
}
|
|
22149
22366
|
|
|
22150
|
-
async readSequence(chr, qstart, qend) {
|
|
22151
22367
|
|
|
22152
|
-
|
|
22153
|
-
|
|
22154
|
-
|
|
22155
|
-
|
|
22156
|
-
|
|
22368
|
+
//Code is losely based on https://github.com/GMOD/bgzf-filehandle
|
|
22369
|
+
//Reworked however in orde to work with the igvxhr interface for loading files
|
|
22370
|
+
//Additionally, replaced calls to the Long.js interface with standard JS calls for ArrayBuffers and the associated views
|
|
22371
|
+
//
|
|
22372
|
+
//The compressed index is an array of blocks, with each block being a pair: compressed-position & uncompressed-position (both in bytes)
|
|
22373
|
+
async getCompressedIndex() {
|
|
22374
|
+
const GZI_NUM_BYTES_OFFSET = 8;
|
|
22375
|
+
const GZI_NUM_BYTES_BLOCK = 8;
|
|
22376
|
+
if (this.compressedIndex) {
|
|
22377
|
+
return this.compressedIndex
|
|
22378
|
+
}
|
|
22379
|
+
if (!this.compressedIndexFile) {
|
|
22380
|
+
this.compressedIndex = [];
|
|
22381
|
+
return this.compressedIndex
|
|
22382
|
+
}
|
|
22383
|
+
//In contrast to the 'normal' reference (for which the index is chromosome based), this index is block-based
|
|
22384
|
+
//As such there is not need to make it a hash. An array is sufficient.
|
|
22385
|
+
this.compressedIndex = [];
|
|
22386
|
+
const gziData = await igvxhr.loadArrayBuffer(this.compressedIndexFile, buildOptions(this.config));
|
|
22387
|
+
const givenFileSize = gziData.byteLength;
|
|
22388
|
+
if (givenFileSize < GZI_NUM_BYTES_OFFSET) {
|
|
22389
|
+
console.log("Cannot parse GZI index file: length (" + givenFileSize + " bytes) is insufficient to determine content of index.");
|
|
22390
|
+
return this.compressedIndex
|
|
22391
|
+
}
|
|
22392
|
+
//First 8 bytes are a little endian unsigned bigint (64bit), indicating the number of blocks in the index.
|
|
22393
|
+
const numBlocksBuffer = gziData.slice(0, GZI_NUM_BYTES_OFFSET);
|
|
22394
|
+
const numBlocks = Number((new DataView(numBlocksBuffer)).getBigUint64(0, true));
|
|
22395
|
+
//The remainder of the gzi content are pairs of little endian unsigned bigint (64bit) numbers.
|
|
22396
|
+
//The first of the pair is the compressed position of a block
|
|
22397
|
+
//The second of the pair is the uncompressed position of a block
|
|
22398
|
+
|
|
22399
|
+
//Sanity check:
|
|
22400
|
+
//Is the size of the array-buffer (of the entire file) correct with regards to the number of blocks detailled by the first 8 bytes of the file?
|
|
22401
|
+
//Total file-size should be:
|
|
22402
|
+
// 8 + 2*(num_entries*8) bytes, with the first 8 bytes indicating the number of entries
|
|
22403
|
+
const expectedFileSize = GZI_NUM_BYTES_OFFSET + numBlocks * 2 * GZI_NUM_BYTES_BLOCK;
|
|
22404
|
+
if (givenFileSize != expectedFileSize) {
|
|
22405
|
+
console.log("Incorrect file size of reference genome index. Expected : " + expectedFileSize + ". Received : " + givenFileSize);
|
|
22406
|
+
return this.compressedIndex
|
|
22407
|
+
}
|
|
22408
|
+
|
|
22409
|
+
//Push the first block to the index: the first block always has positions 0 for both the compressed and uncompressed file
|
|
22410
|
+
this.compressedIndex.push([0, 0]);
|
|
22411
|
+
|
|
22412
|
+
//Further process all the blocks of the GZI index, and keep them in memory
|
|
22413
|
+
for (let blockNumber = 0; blockNumber < numBlocks; blockNumber++) {
|
|
22414
|
+
const bufferBlockStart = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK;
|
|
22415
|
+
const bufferBlockEnd = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK + 2 * GZI_NUM_BYTES_BLOCK;
|
|
22416
|
+
const bufferBlock = gziData.slice(bufferBlockStart, bufferBlockEnd);
|
|
22417
|
+
const viewBlock = new DataView(bufferBlock);
|
|
22418
|
+
const compressedPosition = Number(viewBlock.getBigUint64(0, true)); //First 8 bytes
|
|
22419
|
+
const uncompressedPosition = Number(viewBlock.getBigUint64(GZI_NUM_BYTES_BLOCK, true)); //Last 8 bytes
|
|
22420
|
+
this.compressedIndex.push([compressedPosition, uncompressedPosition]);
|
|
22421
|
+
}
|
|
22422
|
+
return this.compressedIndex
|
|
22423
|
+
}
|
|
22424
|
+
|
|
22425
|
+
//The Fasta-index gives a byte-position of the chromosomal sequences within the FASTA file.
|
|
22426
|
+
//These locations need to be remapped to the locations within the zipped reference genome, using the GZI index
|
|
22427
|
+
//This function provides this functionality by
|
|
22428
|
+
//1) taking the indicated start/stop byte locations within the UNCOMPRESSED FASTA file
|
|
22429
|
+
//2) remapping these byte locations to the correct blocks (and associated positions) within the COMPRESSED FASTA file
|
|
22430
|
+
//Subsequently, the calling method can then extract the correct blocks from the compressed FASTA files and uncompressed the data
|
|
22431
|
+
async getRelevantCompressedBlockNumbers(queryPositionStart, queryPositionEnd) {
|
|
22432
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
22433
|
+
//Fallback for impossible values
|
|
22434
|
+
if (queryPositionStart < 0 || queryPositionEnd < 0 || queryPositionEnd < queryPositionStart) {
|
|
22435
|
+
console.log("Incompatible query positions for reference-genome. Start:" + queryPositionStart + " | End:" + queryPositionEnd);
|
|
22436
|
+
return []
|
|
22437
|
+
}
|
|
22438
|
+
//Ensure compressed index is loaded
|
|
22439
|
+
await this.getCompressedIndex();
|
|
22440
|
+
let result = [];
|
|
22441
|
+
//Now search for the correct block-numbers (going from 0 to length(compressed-index)) which overlap with the provided byte-positions
|
|
22442
|
+
const lowestBlockNumber = 0;
|
|
22443
|
+
const highestBlockNumber = this.compressedIndex.length - 1;
|
|
22444
|
+
//Failsafe if for some reason the compressed index wasn't loaded or doesn't contain any data
|
|
22445
|
+
if (this.compressedIndex.length == 0) {
|
|
22446
|
+
console.log("Compressed index does not contain any content");
|
|
22447
|
+
return []
|
|
22448
|
+
}
|
|
22449
|
+
//Failsafe: if the queryPositionStart is greater than the uncompressed-position of the final block,
|
|
22450
|
+
//then this final block is the only possible result
|
|
22451
|
+
if (queryPositionStart > (this.compressedIndex)[highestBlockNumber][UNCOMPRESSED_POSITION]) {
|
|
22452
|
+
return [highestBlockNumber]
|
|
22453
|
+
}
|
|
22454
|
+
|
|
22455
|
+
//Rather than doing a linear search over all blocks, a binary search is done for speed considerations
|
|
22456
|
+
//We are searching for the highest block number for which its position is smaller than the query start position
|
|
22457
|
+
//Afterwards we will simply expand the blocks until the entire query range is covered
|
|
22458
|
+
let searchLow = lowestBlockNumber;
|
|
22459
|
+
let searchHigh = highestBlockNumber;
|
|
22460
|
+
let searchPosition = Math.floor(this.compressedIndex.length / 2);
|
|
22461
|
+
let maxIterations = this.compressedIndex.length + 1;
|
|
22462
|
+
let solutionFound = false;
|
|
22463
|
+
//instead of doing a while(true), this for-loop prevents eternal loops in case of issues
|
|
22464
|
+
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
22465
|
+
const searchUncompressedPosition = (this.compressedIndex)[searchPosition][UNCOMPRESSED_POSITION];
|
|
22466
|
+
const nextSearchUncompressedPosition = (searchPosition < (this.compressedIndex.length - 1)) ? (this.compressedIndex)[searchPosition + 1][UNCOMPRESSED_POSITION] : Infinity;
|
|
22467
|
+
//The query position lies within the current search block
|
|
22468
|
+
if (searchUncompressedPosition <= queryPositionStart && nextSearchUncompressedPosition > queryPositionStart) {
|
|
22469
|
+
solutionFound = true;
|
|
22470
|
+
break //searchPosition is the correct block number index
|
|
22471
|
+
}
|
|
22472
|
+
//Current block lies before the query position
|
|
22473
|
+
else if (searchUncompressedPosition < queryPositionStart) {
|
|
22474
|
+
searchLow = searchPosition + 1;
|
|
22475
|
+
}
|
|
22476
|
+
//Current block lies after the query position
|
|
22477
|
+
else {
|
|
22478
|
+
searchHigh = searchPosition - 1;
|
|
22479
|
+
}
|
|
22480
|
+
searchPosition = Math.ceil((searchHigh - searchLow) / 2) + searchLow;
|
|
22481
|
+
}
|
|
22482
|
+
//If for some reason the binary search did not reveal a correct block index, then we return the empty result
|
|
22483
|
+
if (!solutionFound) {
|
|
22484
|
+
console.log("No blocks within compressed index found that correspond with query positions " + queryPositionStart + "," + queryPositionEnd);
|
|
22485
|
+
console.log(this.compressedIndex);
|
|
22486
|
+
return []
|
|
22487
|
+
}
|
|
22488
|
+
|
|
22489
|
+
//Now extend the result by adding additional blocks until the entire query range is covered
|
|
22490
|
+
result.push(searchPosition);
|
|
22491
|
+
for (let blockIndex = searchPosition + 1; blockIndex < this.compressedIndex.length; blockIndex++) {
|
|
22492
|
+
result.push(blockIndex);
|
|
22493
|
+
const blockUncompressedPosition = (this.compressedIndex)[blockIndex][UNCOMPRESSED_POSITION];
|
|
22494
|
+
if (blockUncompressedPosition >= queryPositionEnd) {
|
|
22495
|
+
break
|
|
22496
|
+
}
|
|
22497
|
+
}
|
|
22498
|
+
|
|
22499
|
+
//It is possible that the query end position lies AFTER the start of the final block
|
|
22500
|
+
//If this is the case, we add a 'fake' negative index which will be interpreted by the loadAndUncompressBlocks method as an indicator
|
|
22501
|
+
//to read until the end of the file
|
|
22502
|
+
const finalRelevantBlock = result[result.length - 1];
|
|
22503
|
+
const finalIndexBlock = this.compressedIndex.length - 1;
|
|
22504
|
+
if (finalRelevantBlock === finalIndexBlock && (this.compressedIndex)[finalRelevantBlock][UNCOMPRESSED_POSITION] < queryPositionEnd) {
|
|
22505
|
+
result.push(-1);
|
|
22506
|
+
}
|
|
22507
|
+
|
|
22508
|
+
return result
|
|
22509
|
+
}
|
|
22510
|
+
|
|
22511
|
+
|
|
22512
|
+
//Load the content from the blockIndices.
|
|
22513
|
+
//This is done on a per-block basis
|
|
22514
|
+
//Content of the first block will be trimmed in order to match the expected offset
|
|
22515
|
+
async loadAndUncompressBlocks(blockIndices, startByte) {
|
|
22516
|
+
const COMPRESSED_POSITION = 0;
|
|
22517
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
22518
|
+
//Normally the compressed index should already exist, we're just makeing sure here
|
|
22519
|
+
await this.getCompressedIndex();
|
|
22520
|
+
|
|
22521
|
+
if (blockIndices.length == 0) {
|
|
22522
|
+
return ""
|
|
22523
|
+
}
|
|
22524
|
+
|
|
22525
|
+
//Storing data in seperate array with indices in order to assert order due to async behaviour of loops
|
|
22526
|
+
let resultCache = Array(blockIndices.length - 1);
|
|
22527
|
+
for (let i = 0; i < blockIndices.length - 1; i++) {
|
|
22528
|
+
const currentBlockNumber = blockIndices[i];
|
|
22529
|
+
const currentBlockInfo = (this.compressedIndex)[currentBlockNumber];
|
|
22530
|
+
const currentBlockCompressedPosition = currentBlockInfo[COMPRESSED_POSITION];
|
|
22531
|
+
|
|
22532
|
+
const nextBlockNumber = blockIndices[i + 1];
|
|
22533
|
+
let compressedBytes = [];
|
|
22534
|
+
if (nextBlockNumber != -1) { //default : read current entire block only
|
|
22535
|
+
const nextBlockInfo = (this.compressedIndex)[nextBlockNumber];
|
|
22536
|
+
const nextBlockCompressedPosition = nextBlockInfo[COMPRESSED_POSITION];
|
|
22537
|
+
const compressedLength = nextBlockCompressedPosition - currentBlockCompressedPosition;
|
|
22538
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
22539
|
+
range: {
|
|
22540
|
+
start: currentBlockCompressedPosition,
|
|
22541
|
+
size: compressedLength
|
|
22542
|
+
}
|
|
22543
|
+
}));
|
|
22544
|
+
} else { // special case for query within final block: read until the end of the file
|
|
22545
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
22546
|
+
range: {
|
|
22547
|
+
start: currentBlockCompressedPosition
|
|
22548
|
+
}
|
|
22549
|
+
}));
|
|
22550
|
+
}
|
|
22551
|
+
//now unzip the compressed bytes, and store them in the resultCache
|
|
22552
|
+
const uncompressedBytes = await unbgzf(compressedBytes);
|
|
22553
|
+
resultCache[i] = uncompressedBytes;
|
|
22554
|
+
}
|
|
22555
|
+
|
|
22556
|
+
//Iterate over the result cache, create sequences from the data, and create a full sequence string from the data
|
|
22557
|
+
let result = "";
|
|
22558
|
+
for (let i = 0; i < resultCache.length; i++) {
|
|
22559
|
+
for (let j = 0; j < resultCache[i].length; j++) {
|
|
22560
|
+
const c = String.fromCharCode(resultCache[i][j]);
|
|
22561
|
+
result = result + c;
|
|
22562
|
+
}
|
|
22563
|
+
}
|
|
22564
|
+
|
|
22565
|
+
//postprocess this data: because entire blocks are read we need to remove the first N bases of the first used block,
|
|
22566
|
+
//which are not included in the original query positions
|
|
22567
|
+
const firstBlockInfo = (this.compressedIndex)[blockIndices[0]];
|
|
22568
|
+
const offset = startByte - firstBlockInfo[UNCOMPRESSED_POSITION];
|
|
22569
|
+
result = result.substring(offset);
|
|
22570
|
+
|
|
22571
|
+
return result
|
|
22572
|
+
}
|
|
22573
|
+
|
|
22574
|
+
|
|
22575
|
+
async readSequence(chr, qstart, qend) {
|
|
22157
22576
|
|
|
22158
22577
|
await this.getIndex();
|
|
22578
|
+
await this.getCompressedIndex(); //This will work even if no compressed index file is set
|
|
22159
22579
|
|
|
22160
22580
|
const idxEntry = this.index[chr];
|
|
22161
22581
|
if (!idxEntry) {
|
|
22162
22582
|
console.log("No index entry for chr: " + chr);
|
|
22163
|
-
|
|
22164
22583
|
// Tag interval with null so we don't try again
|
|
22165
22584
|
this.interval = new GenomicInterval(chr, qstart, qend, null);
|
|
22166
22585
|
return null
|
|
22586
|
+
}
|
|
22167
22587
|
|
|
22168
|
-
|
|
22588
|
+
const start = Math.max(0, qstart); // qstart should never be < 0
|
|
22589
|
+
const end = Math.min(idxEntry.size, qend);
|
|
22590
|
+
const bytesPerLine = idxEntry.bytesPerLine;
|
|
22591
|
+
const basesPerLine = idxEntry.basesPerLine;
|
|
22592
|
+
const position = idxEntry.position;
|
|
22593
|
+
const nEndBytes = bytesPerLine - basesPerLine;
|
|
22594
|
+
const startLine = Math.floor(start / basesPerLine);
|
|
22595
|
+
const endLine = Math.floor(end / basesPerLine);
|
|
22596
|
+
const base0 = startLine * basesPerLine; // Base at beginning of start line
|
|
22597
|
+
const offset = start - base0;
|
|
22598
|
+
const startByte = position + startLine * bytesPerLine + offset;
|
|
22599
|
+
const base1 = endLine * basesPerLine;
|
|
22600
|
+
const offset1 = end - base1;
|
|
22601
|
+
const endByte = position + endLine * bytesPerLine + offset1 - 1;
|
|
22602
|
+
const byteCount = endByte - startByte + 1;
|
|
22603
|
+
|
|
22604
|
+
if (byteCount <= 0) {
|
|
22605
|
+
console.error("No sequence for " + chr + ":" + qstart + "-" + qend);
|
|
22606
|
+
return null
|
|
22607
|
+
}
|
|
22169
22608
|
|
|
22170
|
-
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22177
|
-
|
|
22178
|
-
|
|
22179
|
-
|
|
22180
|
-
|
|
22181
|
-
|
|
22182
|
-
|
|
22183
|
-
|
|
22184
|
-
|
|
22185
|
-
|
|
22186
|
-
|
|
22187
|
-
if (byteCount <= 0) {
|
|
22188
|
-
console.error("No sequence for " + chr + ":" + qstart + "-" + qend);
|
|
22189
|
-
} else {
|
|
22190
|
-
allBytes = await igvxhr.load(this.file, buildOptions(this.config, {
|
|
22191
|
-
range: {
|
|
22192
|
-
start: startByte,
|
|
22193
|
-
size: byteCount
|
|
22194
|
-
}
|
|
22195
|
-
}));
|
|
22609
|
+
//If the compressed index file is set, then we are dealing with a compressed genome sequence
|
|
22610
|
+
//The selection of startByte/endByte is done for the non-compressed genome sequence.
|
|
22611
|
+
//These need to be 'converted' to the correct byte positions in the compressed genome sequence,
|
|
22612
|
+
//by making use of the compressed index (GZI file)
|
|
22613
|
+
let allBytes;
|
|
22614
|
+
if (!this.compressedIndexFile) {
|
|
22615
|
+
allBytes = await igvxhr.load(this.file, buildOptions(this.config, {
|
|
22616
|
+
range: {
|
|
22617
|
+
start: startByte,
|
|
22618
|
+
size: byteCount
|
|
22619
|
+
}
|
|
22620
|
+
}));
|
|
22621
|
+
} else {
|
|
22622
|
+
let relevantBlockIndices = await this.getRelevantCompressedBlockNumbers(startByte, endByte);
|
|
22623
|
+
if (relevantBlockIndices.length === 0) {
|
|
22624
|
+
console.log("No blocks in the compressed index that correspond with the requested byte positions (" + startByte + "," + endByte + ")");
|
|
22625
|
+
return null
|
|
22196
22626
|
}
|
|
22627
|
+
allBytes = await this.loadAndUncompressBlocks(relevantBlockIndices, startByte);
|
|
22628
|
+
}
|
|
22197
22629
|
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
let nBases,
|
|
22202
|
-
seqBytes = "",
|
|
22203
|
-
srcPos = 0,
|
|
22204
|
-
allBytesLength = allBytes.length;
|
|
22630
|
+
if (!allBytes) {
|
|
22631
|
+
return null
|
|
22632
|
+
}
|
|
22205
22633
|
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
}
|
|
22634
|
+
let nBases,
|
|
22635
|
+
seqBytes = "",
|
|
22636
|
+
srcPos = 0,
|
|
22637
|
+
allBytesLength = allBytes.length;
|
|
22211
22638
|
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22639
|
+
if (offset > 0) {
|
|
22640
|
+
nBases = Math.min(end - start, basesPerLine - offset);
|
|
22641
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
22642
|
+
srcPos += (nBases + nEndBytes);
|
|
22643
|
+
}
|
|
22217
22644
|
|
|
22218
|
-
|
|
22219
|
-
|
|
22645
|
+
while (srcPos < allBytesLength) {
|
|
22646
|
+
nBases = Math.min(basesPerLine, allBytesLength - srcPos);
|
|
22647
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
22648
|
+
srcPos += (nBases + nEndBytes);
|
|
22220
22649
|
}
|
|
22650
|
+
|
|
22651
|
+
return seqBytes
|
|
22652
|
+
|
|
22221
22653
|
}
|
|
22222
22654
|
}
|
|
22223
22655
|
|
|
@@ -22329,7 +22761,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
22329
22761
|
}
|
|
22330
22762
|
};
|
|
22331
22763
|
|
|
22332
|
-
const _version = "2.
|
|
22764
|
+
const _version = "2.11.2";
|
|
22333
22765
|
function version() {
|
|
22334
22766
|
return _version
|
|
22335
22767
|
}
|
|
@@ -22856,7 +23288,9 @@ class TrackViewport extends Viewport {
|
|
|
22856
23288
|
}
|
|
22857
23289
|
|
|
22858
23290
|
stopSpinner() {
|
|
22859
|
-
this.$spinner
|
|
23291
|
+
if (this.$spinner) {
|
|
23292
|
+
this.$spinner.hide();
|
|
23293
|
+
}
|
|
22860
23294
|
}
|
|
22861
23295
|
|
|
22862
23296
|
checkZoomIn() {
|
|
@@ -23183,7 +23617,7 @@ class TrackViewport extends Viewport {
|
|
|
23183
23617
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23184
23618
|
|
|
23185
23619
|
const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
|
|
23186
|
-
const id = `${str}_referenceFrame_${index}_guid_${guid$
|
|
23620
|
+
const id = `${str}_referenceFrame_${index}_guid_${guid$2()}`;
|
|
23187
23621
|
|
|
23188
23622
|
this.drawSVGWithContext(context, width, height, id, 0, 0, 0);
|
|
23189
23623
|
|
|
@@ -23206,7 +23640,7 @@ class TrackViewport extends Viewport {
|
|
|
23206
23640
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23207
23641
|
|
|
23208
23642
|
const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
|
|
23209
|
-
const id = `${str}_referenceFrame_${index}_guid_${guid$
|
|
23643
|
+
const id = `${str}_referenceFrame_${index}_guid_${guid$2()}`;
|
|
23210
23644
|
|
|
23211
23645
|
const {top: yScrollDelta} = this.$content.position();
|
|
23212
23646
|
|
|
@@ -23225,7 +23659,7 @@ class TrackViewport extends Viewport {
|
|
|
23225
23659
|
renderTrackLabelSVG(context, tx, ty, width, height) {
|
|
23226
23660
|
|
|
23227
23661
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23228
|
-
const id = `${str}_track_label_guid_${guid$
|
|
23662
|
+
const id = `${str}_track_label_guid_${guid$2()}`;
|
|
23229
23663
|
|
|
23230
23664
|
context.saveWithTranslationAndClipRect(id, tx, ty, width, height, 0);
|
|
23231
23665
|
|
|
@@ -23552,28 +23986,16 @@ class TrackViewport extends Viewport {
|
|
|
23552
23986
|
str = track.description();
|
|
23553
23987
|
} else if (track.description) {
|
|
23554
23988
|
str = `<div>${track.description}</div>`;
|
|
23555
|
-
} else {
|
|
23556
|
-
if (track.url) {
|
|
23557
|
-
if (isFile(track.url)) {
|
|
23558
|
-
str = `<div><b>Filename: </b>${track.url.name}`;
|
|
23559
|
-
} else {
|
|
23560
|
-
str = `<div><b>URL: </b>${track.url}`;
|
|
23561
|
-
}
|
|
23562
|
-
} else {
|
|
23563
|
-
str = track.name;
|
|
23564
|
-
|
|
23565
|
-
}
|
|
23566
23989
|
}
|
|
23567
23990
|
|
|
23568
|
-
if (
|
|
23569
|
-
this.popover
|
|
23991
|
+
if (str) {
|
|
23992
|
+
if (this.popover) {
|
|
23993
|
+
this.popover.dispose();
|
|
23994
|
+
}
|
|
23995
|
+
this.popover = new Popover(this.browser.columnContainer, (track.name || ''));
|
|
23996
|
+
this.popover.presentContentWithEvent(event, str);
|
|
23570
23997
|
}
|
|
23571
|
-
|
|
23572
|
-
this.popover = new Popover(this.browser.columnContainer, (track.name || 'unnamed'));
|
|
23573
|
-
|
|
23574
|
-
this.popover.presentContentWithEvent(event, str);
|
|
23575
23998
|
}
|
|
23576
|
-
|
|
23577
23999
|
}
|
|
23578
24000
|
|
|
23579
24001
|
removeTrackLabelClickHandler(trackLabel) {
|
|
@@ -28743,7 +29165,7 @@ class TrackBase {
|
|
|
28743
29165
|
this.config = config;
|
|
28744
29166
|
this.url = config.url;
|
|
28745
29167
|
this.type = config.type;
|
|
28746
|
-
|
|
29168
|
+
|
|
28747
29169
|
this.supportHiDPI = config.supportHiDPI === undefined ? true : config.supportHiDPI;
|
|
28748
29170
|
|
|
28749
29171
|
if (config.name || config.label) {
|
|
@@ -28781,6 +29203,15 @@ class TrackBase {
|
|
|
28781
29203
|
this.onclick = config.onclick;
|
|
28782
29204
|
config.onclick = undefined; // functions cannot be saved in sessions, clear it here.
|
|
28783
29205
|
}
|
|
29206
|
+
|
|
29207
|
+
if (config.description) {
|
|
29208
|
+
// Override description -- displayed when clicking on track label. Convert to function if neccessary
|
|
29209
|
+
if (typeof config.description === 'function') {
|
|
29210
|
+
this.description = config.description;
|
|
29211
|
+
} else {
|
|
29212
|
+
this.description = () => config.description;
|
|
29213
|
+
}
|
|
29214
|
+
}
|
|
28784
29215
|
}
|
|
28785
29216
|
|
|
28786
29217
|
get name() {
|
|
@@ -28823,7 +29254,7 @@ class TrackBase {
|
|
|
28823
29254
|
for (let key of Object.keys(state)) {
|
|
28824
29255
|
if (key.startsWith("_")) continue // transient property
|
|
28825
29256
|
const value = this[key];
|
|
28826
|
-
if (value && (isSimpleType(value) || typeof value === "boolean")) {
|
|
29257
|
+
if (value && (isSimpleType(value) || typeof value === "boolean" || key === "metadata")) {
|
|
28827
29258
|
state[key] = value;
|
|
28828
29259
|
}
|
|
28829
29260
|
}
|
|
@@ -28837,16 +29268,18 @@ class TrackBase {
|
|
|
28837
29268
|
state.max = this.dataRange.max;
|
|
28838
29269
|
}
|
|
28839
29270
|
|
|
29271
|
+
|
|
28840
29272
|
// Check for non-json-if-yable properties. Perhaps we should test what can be saved.
|
|
28841
29273
|
for (let key of Object.keys(state)) {
|
|
28842
|
-
|
|
29274
|
+
const value = state[key];
|
|
29275
|
+
if (typeof value === 'function') {
|
|
28843
29276
|
throw Error(`Property '${key}' of track '${this.name} is a function. Functions cannot be saved in sessions.`)
|
|
28844
29277
|
}
|
|
28845
|
-
if (
|
|
29278
|
+
if (value instanceof File) { // Test specifically for File. Other types of File-like objects might be savable
|
|
28846
29279
|
const str = `Track ${this.name} is a local file. Sessions cannot be saved with local file references.`;
|
|
28847
29280
|
throw Error(str)
|
|
28848
29281
|
}
|
|
28849
|
-
if (
|
|
29282
|
+
if (value instanceof Promise) {
|
|
28850
29283
|
throw Error(`Property '${key}' of track '${this.name} is a Promise. Promises cannot be saved in sessions.`)
|
|
28851
29284
|
}
|
|
28852
29285
|
}
|
|
@@ -29092,6 +29525,49 @@ class TrackBase {
|
|
|
29092
29525
|
|
|
29093
29526
|
}
|
|
29094
29527
|
|
|
29528
|
+
/**
|
|
29529
|
+
* Default track description -- displayed on click of track label. This can be overriden in the track
|
|
29530
|
+
* configuration, or in subclasses.
|
|
29531
|
+
*/
|
|
29532
|
+
description() {
|
|
29533
|
+
|
|
29534
|
+
const wrapKeyValue = (k, v) => `<div class="igv-track-label-popup-shim"><b>${k}: </b>${v}</div>`;
|
|
29535
|
+
|
|
29536
|
+
let str = '<div class="igv-track-label-popup">';
|
|
29537
|
+
if (this.url) {
|
|
29538
|
+
if (isFile(this.url)) {
|
|
29539
|
+
str += wrapKeyValue('Filename', this.url.name);
|
|
29540
|
+
} else {
|
|
29541
|
+
str += wrapKeyValue('URL', this.url);
|
|
29542
|
+
}
|
|
29543
|
+
} else {
|
|
29544
|
+
str = this.name;
|
|
29545
|
+
}
|
|
29546
|
+
if (this.config) {
|
|
29547
|
+
if (this.config.metadata) {
|
|
29548
|
+
for (let key of Object.keys(this.config.metadata)) {
|
|
29549
|
+
const value = this.config.metadata[key];
|
|
29550
|
+
str += wrapKeyValue(key, value);
|
|
29551
|
+
}
|
|
29552
|
+
}
|
|
29553
|
+
|
|
29554
|
+
// Add any config properties that are capitalized
|
|
29555
|
+
for (let key of Object.keys(this.config)) {
|
|
29556
|
+
if (key.startsWith("_")) continue // transient property
|
|
29557
|
+
let first = key.substr(0, 1);
|
|
29558
|
+
if (first !== first.toLowerCase()) {
|
|
29559
|
+
const value = this.config[key];
|
|
29560
|
+
if (value && isSimpleType(value)) {
|
|
29561
|
+
str += wrapKeyValue(key, value);
|
|
29562
|
+
}
|
|
29563
|
+
}
|
|
29564
|
+
}
|
|
29565
|
+
|
|
29566
|
+
}
|
|
29567
|
+
str += '</div>';
|
|
29568
|
+
return str
|
|
29569
|
+
}
|
|
29570
|
+
|
|
29095
29571
|
static getCravatLink(chr, position, ref, alt, genomeID) {
|
|
29096
29572
|
|
|
29097
29573
|
if ("hg38" === genomeID || "GRCh38" === genomeID) {
|
|
@@ -29138,6 +29614,8 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29138
29614
|
return
|
|
29139
29615
|
}
|
|
29140
29616
|
|
|
29617
|
+
let flipAxis = (undefined === this.flipAxis) ? false : this.flipAxis;
|
|
29618
|
+
|
|
29141
29619
|
IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
29142
29620
|
|
|
29143
29621
|
reference = 0.95 * pixelWidth;
|
|
@@ -29152,7 +29630,7 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29152
29630
|
|
|
29153
29631
|
// tick
|
|
29154
29632
|
IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font);
|
|
29155
|
-
IGVGraphics.fillText(ctx, prettyPrint(this.dataRange.max), x1 + 4, y1 + 12, font);
|
|
29633
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.min : this.dataRange.max), x1 + 4, y1 + 12, font);
|
|
29156
29634
|
|
|
29157
29635
|
//shim = 0.25 * 0.125;
|
|
29158
29636
|
y1 = y2 = (1.0 - shim) * pixelHeight;
|
|
@@ -29161,7 +29639,7 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29161
29639
|
|
|
29162
29640
|
// tick
|
|
29163
29641
|
IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font);
|
|
29164
|
-
IGVGraphics.fillText(ctx, prettyPrint(this.dataRange.min), x1 + 4, y1 - 4, font);
|
|
29642
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max : this.dataRange.min), x1 + 4, y1 - 4, font);
|
|
29165
29643
|
|
|
29166
29644
|
IGVGraphics.strokeLine(ctx, a.x, a.y, b.x, b.y, font);
|
|
29167
29645
|
|
|
@@ -30566,6 +31044,75 @@ const chrColorMap$1 = {
|
|
|
30566
31044
|
"chr48": "rgb(20, 255, 177)",
|
|
30567
31045
|
};
|
|
30568
31046
|
|
|
31047
|
+
class ChordSetManager {
|
|
31048
|
+
|
|
31049
|
+
constructor(config) {
|
|
31050
|
+
this.tracks = [];
|
|
31051
|
+
this.chordSets = [];
|
|
31052
|
+
}
|
|
31053
|
+
|
|
31054
|
+
addChordSet(chordSet) {
|
|
31055
|
+
|
|
31056
|
+
// If a chord set with this name exists replace it (same track, same region)
|
|
31057
|
+
this.chordSets = this.chordSets.filter(g => g.name !== chordSet.name);
|
|
31058
|
+
this.chordSets.push(chordSet);
|
|
31059
|
+
|
|
31060
|
+
let track = this.tracks.find(t => chordSet.trackName === t.name);
|
|
31061
|
+
if (track) {
|
|
31062
|
+
track.chordSets = track.chordSets.filter(cs => cs.name !== chordSet.name);
|
|
31063
|
+
track.chordSets.push(chordSet);
|
|
31064
|
+
}
|
|
31065
|
+
if (!track) {
|
|
31066
|
+
track = new IGVTrack(chordSet);
|
|
31067
|
+
this.tracks.push(track);
|
|
31068
|
+
}
|
|
31069
|
+
}
|
|
31070
|
+
|
|
31071
|
+
clearChords() {
|
|
31072
|
+
this.tracks = [];
|
|
31073
|
+
this.chordSets = [];
|
|
31074
|
+
}
|
|
31075
|
+
|
|
31076
|
+
getTrack(name) {
|
|
31077
|
+
return this.tracks.find(t => name === t.name)
|
|
31078
|
+
}
|
|
31079
|
+
|
|
31080
|
+
getChordset(name) {
|
|
31081
|
+
return this.chordSets.find(cs => name === cs.name)
|
|
31082
|
+
}
|
|
31083
|
+
|
|
31084
|
+
}
|
|
31085
|
+
|
|
31086
|
+
class IGVTrack {
|
|
31087
|
+
constructor(chordSet) {
|
|
31088
|
+
this.name = chordSet.trackName;
|
|
31089
|
+
this.color = chordSet.trackColor;
|
|
31090
|
+
this.visible = true;
|
|
31091
|
+
this.chordSets = [chordSet];
|
|
31092
|
+
this.id = guid$1();
|
|
31093
|
+
}
|
|
31094
|
+
|
|
31095
|
+
get chords() {
|
|
31096
|
+
if (this.chordSets.length === 1) {
|
|
31097
|
+
return this.chordSets[0].chords
|
|
31098
|
+
}
|
|
31099
|
+
const chords = [];
|
|
31100
|
+
for (let cs of this.chordSets) {
|
|
31101
|
+
for (let c of cs.chords) {
|
|
31102
|
+
chords.push(c);
|
|
31103
|
+
}
|
|
31104
|
+
}
|
|
31105
|
+
return chords
|
|
31106
|
+
}
|
|
31107
|
+
}
|
|
31108
|
+
|
|
31109
|
+
|
|
31110
|
+
function guid$1() {
|
|
31111
|
+
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
|
|
31112
|
+
}
|
|
31113
|
+
|
|
31114
|
+
const EXP5 = Math.exp(5);
|
|
31115
|
+
|
|
30569
31116
|
class CircularView {
|
|
30570
31117
|
|
|
30571
31118
|
static isInstalled() {
|
|
@@ -30590,6 +31137,8 @@ class CircularView {
|
|
|
30590
31137
|
if (CircularView.isInstalled()) {
|
|
30591
31138
|
|
|
30592
31139
|
this.parent = parent;
|
|
31140
|
+
this.groupByTrack = config.groupByTrack === true;
|
|
31141
|
+
this.chordManager = new ChordSetManager(config);
|
|
30593
31142
|
|
|
30594
31143
|
// wrapper for toolbar and circular-view container
|
|
30595
31144
|
const wrapper = document.createElement('div');
|
|
@@ -30597,7 +31146,8 @@ class CircularView {
|
|
|
30597
31146
|
parent.appendChild(wrapper);
|
|
30598
31147
|
|
|
30599
31148
|
// toolbar
|
|
30600
|
-
this.
|
|
31149
|
+
this.createControls(wrapper);
|
|
31150
|
+
this.resetControlPanel();
|
|
30601
31151
|
|
|
30602
31152
|
// circular view container
|
|
30603
31153
|
const element = document.createElement('div');
|
|
@@ -30609,8 +31159,6 @@ class CircularView {
|
|
|
30609
31159
|
this.setAssembly(config.assembly);
|
|
30610
31160
|
}
|
|
30611
31161
|
|
|
30612
|
-
this.tracks = config.tracks || [];
|
|
30613
|
-
|
|
30614
31162
|
this.width = config.width || 500;
|
|
30615
31163
|
this.height = config.height || 500;
|
|
30616
31164
|
this.setSize(this.width, this.height);
|
|
@@ -30620,55 +31168,47 @@ class CircularView {
|
|
|
30620
31168
|
}
|
|
30621
31169
|
}
|
|
30622
31170
|
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
let element;
|
|
31171
|
+
createControls(parent) {
|
|
30626
31172
|
|
|
30627
31173
|
// toolbar
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
parent.appendChild(
|
|
30631
|
-
this.toolbar =
|
|
31174
|
+
const toolbarDiv = document.createElement('div');
|
|
31175
|
+
toolbarDiv.className = 'igv-circview-toolbar';
|
|
31176
|
+
parent.appendChild(toolbarDiv);
|
|
31177
|
+
this.toolbar = toolbarDiv;
|
|
30632
31178
|
|
|
30633
|
-
|
|
30634
|
-
|
|
30635
|
-
|
|
30636
|
-
|
|
30637
|
-
|
|
30638
|
-
this.
|
|
30639
|
-
|
|
30640
|
-
this.trackPanel.style.display = 'none';
|
|
31179
|
+
// control panel
|
|
31180
|
+
const controlPanelDiv = document.createElement('div');
|
|
31181
|
+
controlPanelDiv.className = 'igv-circview-track-panel';
|
|
31182
|
+
parent.appendChild(controlPanelDiv);
|
|
31183
|
+
this.controlPanel = controlPanelDiv;
|
|
31184
|
+
this.controlPanel.style.display = 'none';
|
|
30641
31185
|
|
|
30642
31186
|
|
|
30643
31187
|
// toolbar button container - Track Options - Clear All
|
|
30644
|
-
|
|
31188
|
+
const buttonContainer = document.createElement('div');
|
|
30645
31189
|
buttonContainer.className = 'igv-circview-toolbar-button-container';
|
|
30646
31190
|
this.toolbar.appendChild(buttonContainer);
|
|
30647
31191
|
|
|
30648
|
-
//
|
|
30649
|
-
this.
|
|
30650
|
-
this.
|
|
30651
|
-
buttonContainer.appendChild(this.
|
|
30652
|
-
this.
|
|
30653
|
-
this.
|
|
30654
|
-
|
|
30655
|
-
const trackPanelRows = this.trackPanel.querySelectorAll('div');
|
|
30656
|
-
|
|
31192
|
+
// Show Controls
|
|
31193
|
+
this.showControlsButton = document.createElement('div');
|
|
31194
|
+
this.showControlsButton.className = 'igv-circview-button';
|
|
31195
|
+
buttonContainer.appendChild(this.showControlsButton);
|
|
31196
|
+
this.showControlsButton.innerText = 'none' === this.controlPanel.style.display ? 'Show Controls' : 'Hide Controls';
|
|
31197
|
+
this.showControlsButton.addEventListener('click', (event) => {
|
|
31198
|
+
const trackPanelRows = this.controlPanel.querySelectorAll('div');
|
|
30657
31199
|
if (trackPanelRows.length > 0) {
|
|
30658
31200
|
|
|
30659
|
-
if ('none' === this.
|
|
30660
|
-
this.
|
|
30661
|
-
event.target.innerText = 'Hide
|
|
31201
|
+
if ('none' === this.controlPanel.style.display) {
|
|
31202
|
+
this.controlPanel.style.display = 'flex';
|
|
31203
|
+
event.target.innerText = 'Hide Controls';
|
|
30662
31204
|
} else {
|
|
30663
|
-
this.
|
|
30664
|
-
event.target.innerText = 'Show
|
|
31205
|
+
this.controlPanel.style.display = 'none';
|
|
31206
|
+
event.target.innerText = 'Show Controls';
|
|
30665
31207
|
}
|
|
30666
|
-
|
|
30667
31208
|
}
|
|
30668
|
-
|
|
30669
31209
|
});
|
|
30670
31210
|
|
|
30671
|
-
// Clear All
|
|
31211
|
+
// Clear All
|
|
30672
31212
|
let button = document.createElement('div');
|
|
30673
31213
|
button.className = 'igv-circview-button';
|
|
30674
31214
|
buttonContainer.appendChild(button);
|
|
@@ -30677,14 +31217,8 @@ class CircularView {
|
|
|
30677
31217
|
this.clearChords();
|
|
30678
31218
|
});
|
|
30679
31219
|
|
|
30680
|
-
|
|
30681
|
-
|
|
30682
|
-
buttonContainer = document.createElement('div');
|
|
30683
|
-
buttonContainer.className = 'igv-circview-toolbar-button-container';
|
|
30684
|
-
this.toolbar.appendChild(buttonContainer);
|
|
30685
|
-
|
|
30686
|
-
// Close Window
|
|
30687
|
-
if(false !== this.config.showCloseButton) {
|
|
31220
|
+
// Close
|
|
31221
|
+
if (false !== this.config.showCloseButton) {
|
|
30688
31222
|
button = document.createElement('div');
|
|
30689
31223
|
button.className = 'igv-circview-button';
|
|
30690
31224
|
buttonContainer.appendChild(button);
|
|
@@ -30693,60 +31227,115 @@ class CircularView {
|
|
|
30693
31227
|
this.visible = false;
|
|
30694
31228
|
});
|
|
30695
31229
|
}
|
|
31230
|
+
}
|
|
30696
31231
|
|
|
31232
|
+
resetControlPanel() {
|
|
31233
|
+
this.controlPanel.innerHTML = '';
|
|
31234
|
+
this.controlPanel.appendChild(this.createGroupByCB());
|
|
31235
|
+
const chordSets = this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets;
|
|
31236
|
+
for(let cs of chordSets) {
|
|
31237
|
+
this.addToControlPanel(cs);
|
|
31238
|
+
}
|
|
30697
31239
|
}
|
|
30698
31240
|
|
|
30699
|
-
|
|
31241
|
+
createGroupByCB() {
|
|
31242
|
+
const groupByCB = document.createElement('input');
|
|
31243
|
+
groupByCB.type = 'checkbox';
|
|
31244
|
+
groupByCB.id = 'groupByCB';
|
|
31245
|
+
groupByCB.style.width = '1.4em';
|
|
31246
|
+
groupByCB.style.height = '1.4em';
|
|
31247
|
+
groupByCB.checked = this.groupByTrack;
|
|
30700
31248
|
|
|
30701
|
-
|
|
31249
|
+
groupByCB.onclick = (evt) => {
|
|
31250
|
+
this.groupByTrack = evt.target.checked;
|
|
31251
|
+
this.resetControlPanel();
|
|
31252
|
+
this.render();
|
|
31253
|
+
};
|
|
31254
|
+
|
|
31255
|
+
const groupByLabel = document.createElement('label');
|
|
31256
|
+
groupByLabel.for = 'groupByCB';
|
|
31257
|
+
groupByLabel.innerText = 'Group by track';
|
|
31258
|
+
groupByLabel.style.color = 'black';
|
|
31259
|
+
groupByLabel.style.paddingLeft = '10px';
|
|
30702
31260
|
const trackPanelRow = document.createElement('div');
|
|
30703
|
-
|
|
31261
|
+
trackPanelRow.style.width = '100%';
|
|
31262
|
+
trackPanelRow.style.paddingTop = '5px';
|
|
31263
|
+
trackPanelRow.style.paddingBottom = '5px';
|
|
31264
|
+
trackPanelRow.style.background = 'rgb(216, 230, 234)';
|
|
31265
|
+
trackPanelRow.appendChild(groupByCB);
|
|
31266
|
+
trackPanelRow.appendChild(groupByLabel);
|
|
31267
|
+
return trackPanelRow
|
|
31268
|
+
}
|
|
30704
31269
|
|
|
31270
|
+
addToControlPanel(chordSet) {
|
|
31271
|
+
|
|
31272
|
+
// single track row - container for hide-button | color-picker-swatch | track-name
|
|
31273
|
+
const row = document.createElement('div');
|
|
31274
|
+
this.controlPanel.appendChild(row);
|
|
30705
31275
|
|
|
30706
|
-
let element;
|
|
30707
31276
|
|
|
30708
31277
|
// track hide|show
|
|
30709
|
-
|
|
30710
|
-
|
|
30711
|
-
|
|
30712
|
-
|
|
30713
|
-
|
|
30714
|
-
if (true ===
|
|
30715
|
-
this.hideTrack(
|
|
31278
|
+
const hideShowButton = document.createElement('div');
|
|
31279
|
+
hideShowButton.className = 'igv-circview-button';
|
|
31280
|
+
row.appendChild(hideShowButton);
|
|
31281
|
+
hideShowButton.innerText = true === chordSet.visible ? 'Hide' : 'Show';
|
|
31282
|
+
hideShowButton.addEventListener('click', event => {
|
|
31283
|
+
if (true === chordSet.visible) {
|
|
31284
|
+
this.hideTrack(chordSet.name);
|
|
30716
31285
|
event.target.innerText = "Show";
|
|
30717
31286
|
} else {
|
|
30718
|
-
this.showTrack(
|
|
31287
|
+
this.showTrack(chordSet.name);
|
|
30719
31288
|
event.target.innerText = "Hide";
|
|
30720
31289
|
}
|
|
30721
|
-
|
|
30722
31290
|
});
|
|
30723
31291
|
|
|
30724
|
-
//
|
|
30725
|
-
|
|
30726
|
-
const
|
|
30727
|
-
|
|
30728
|
-
|
|
30729
|
-
|
|
30730
|
-
|
|
31292
|
+
// The alpha range slider. Create this here so we can reference it from the color picker
|
|
31293
|
+
const alphaSlider = document.createElement('input');
|
|
31294
|
+
const valueToAlpha = (value) => Math.exp(value / 200) / EXP5;
|
|
31295
|
+
const alphaToValue = (alpha) => 200 * Math.log(alpha * EXP5);
|
|
31296
|
+
|
|
31297
|
+
// color
|
|
31298
|
+
const colorPickerButton = document.createElement('div');
|
|
31299
|
+
colorPickerButton.className = 'igv-circview-button';
|
|
31300
|
+
colorPickerButton.innerHTML = ' '; // <- important for button to size properly
|
|
31301
|
+
row.appendChild(colorPickerButton);
|
|
31302
|
+
colorPickerButton.style.backgroundColor = setAlpha(chordSet.color, 1);
|
|
30731
31303
|
const pickerConfig =
|
|
30732
31304
|
{
|
|
30733
|
-
parent:
|
|
31305
|
+
parent: colorPickerButton,
|
|
30734
31306
|
popup: 'right',
|
|
30735
31307
|
editorFormat: 'rgb',
|
|
30736
|
-
color:
|
|
31308
|
+
color: chordSet.color,
|
|
30737
31309
|
onChange: ({rgbaString}) => {
|
|
30738
|
-
|
|
30739
|
-
this.setTrackColor(
|
|
31310
|
+
colorPickerButton.style.backgroundColor = setAlpha(rgbaString, 1);
|
|
31311
|
+
this.setTrackColor(chordSet.name, rgbaString);
|
|
31312
|
+
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
30740
31313
|
}
|
|
30741
31314
|
};
|
|
30742
|
-
|
|
30743
|
-
|
|
31315
|
+
const picker = new Picker(pickerConfig);
|
|
31316
|
+
|
|
31317
|
+
// alpha transparency
|
|
31318
|
+
alphaSlider.setAttribute('title', 'Adjust transparency of arcs');
|
|
31319
|
+
alphaSlider.type = 'range';
|
|
31320
|
+
//alphaSlider.className = 'igv-circview-alpha-slider'
|
|
31321
|
+
alphaSlider.style.width = '100px';
|
|
31322
|
+
alphaSlider.style.marginRight = '10px';
|
|
31323
|
+
alphaSlider.setAttribute('class', 'range');
|
|
31324
|
+
alphaSlider.setAttribute('min', '0');
|
|
31325
|
+
alphaSlider.setAttribute('max', '1000');
|
|
31326
|
+
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
31327
|
+
alphaSlider.oninput = () => {
|
|
31328
|
+
const v = valueToAlpha(alphaSlider.value);
|
|
31329
|
+
this.setTrackColor(chordSet.name, setAlpha(chordSet.color, v));
|
|
31330
|
+
picker.setColor(chordSet.color);
|
|
31331
|
+
};
|
|
31332
|
+
row.appendChild(alphaSlider);
|
|
30744
31333
|
|
|
30745
31334
|
// track name
|
|
30746
|
-
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
|
|
31335
|
+
const trackNameDive = document.createElement('div');
|
|
31336
|
+
trackNameDive.style.color = 'black';
|
|
31337
|
+
row.appendChild(trackNameDive);
|
|
31338
|
+
trackNameDive.innerText = trackNameDive.title = chordSet.name;
|
|
30750
31339
|
|
|
30751
31340
|
}
|
|
30752
31341
|
|
|
@@ -30760,7 +31349,7 @@ class CircularView {
|
|
|
30760
31349
|
if (this.genomeId === igvGenome.id) {
|
|
30761
31350
|
return
|
|
30762
31351
|
}
|
|
30763
|
-
this.
|
|
31352
|
+
this.chordManager.clearChords();
|
|
30764
31353
|
this.genomeId = igvGenome.id;
|
|
30765
31354
|
this.chrNames = new Set(igvGenome.chromosomes.map(chr => shortChrName$1(chr.name)));
|
|
30766
31355
|
|
|
@@ -30823,39 +31412,24 @@ class CircularView {
|
|
|
30823
31412
|
|
|
30824
31413
|
addChords(newChords, options = {}) {
|
|
30825
31414
|
|
|
30826
|
-
const
|
|
31415
|
+
const tmp = options.track || options.name || "*";
|
|
31416
|
+
const trackName = tmp.split(' ')[0].replaceAll("%20", " ");
|
|
31417
|
+
const chordSetName = tmp.replaceAll("%20", " ");
|
|
31418
|
+
|
|
31419
|
+
const chordSet = {
|
|
31420
|
+
name: chordSetName,
|
|
31421
|
+
trackName: trackName,
|
|
31422
|
+
chords: newChords,
|
|
31423
|
+
color: options.color || "black",
|
|
31424
|
+
trackColor: options.trackColor || options.color || "black",
|
|
31425
|
+
visible: true,
|
|
31426
|
+
id: options.id || guid()
|
|
31427
|
+
};
|
|
30827
31428
|
|
|
30828
|
-
|
|
31429
|
+
this.chordManager.addChordSet(chordSet);
|
|
30829
31430
|
|
|
30830
|
-
|
|
30831
|
-
if (track) {
|
|
30832
|
-
if (options.color) {
|
|
30833
|
-
track.color = options.color;
|
|
30834
|
-
}
|
|
30835
|
-
} else {
|
|
30836
|
-
track =
|
|
30837
|
-
{
|
|
30838
|
-
name,
|
|
30839
|
-
chords: [],
|
|
30840
|
-
color: options.color || "black",
|
|
30841
|
-
visible: true,
|
|
30842
|
-
id: options.id || guid()
|
|
30843
|
-
};
|
|
30844
|
-
this.tracks.push(track);
|
|
30845
|
-
|
|
30846
|
-
this.addToTrackPanel(track);
|
|
30847
|
-
}
|
|
31431
|
+
this.resetControlPanel();
|
|
30848
31432
|
|
|
30849
|
-
// Append chords to track
|
|
30850
|
-
const currentIDs = new Set(track.chords.map(c => c.uniqueId));
|
|
30851
|
-
for (let c of newChords) {
|
|
30852
|
-
if (!currentIDs.has(c.uniqueId) &&
|
|
30853
|
-
this.chrNames.has(shortChrName$1(c.refName)) &&
|
|
30854
|
-
this.chrNames.has(shortChrName$1(c.mate.refName))) {
|
|
30855
|
-
track.chords.push(c);
|
|
30856
|
-
currentIDs.add(c.uniqueId);
|
|
30857
|
-
}
|
|
30858
|
-
}
|
|
30859
31433
|
this.render();
|
|
30860
31434
|
}
|
|
30861
31435
|
|
|
@@ -30881,8 +31455,9 @@ class CircularView {
|
|
|
30881
31455
|
}
|
|
30882
31456
|
|
|
30883
31457
|
clearChords() {
|
|
30884
|
-
this.tracks = []
|
|
30885
|
-
this.
|
|
31458
|
+
//this.tracks = []
|
|
31459
|
+
this.chordManager.clearChords();
|
|
31460
|
+
this.resetControlPanel();
|
|
30886
31461
|
this.render();
|
|
30887
31462
|
}
|
|
30888
31463
|
|
|
@@ -30927,8 +31502,8 @@ class CircularView {
|
|
|
30927
31502
|
this.parent.style.display = isVisible ? 'block' : 'none';
|
|
30928
31503
|
}
|
|
30929
31504
|
|
|
30930
|
-
hideTrack(
|
|
30931
|
-
let track = this.
|
|
31505
|
+
hideTrack(trackName) {
|
|
31506
|
+
let track = this.getTrack(trackName);
|
|
30932
31507
|
if (track) {
|
|
30933
31508
|
track.visible = false;
|
|
30934
31509
|
this.render();
|
|
@@ -30937,34 +31512,44 @@ class CircularView {
|
|
|
30937
31512
|
}
|
|
30938
31513
|
}
|
|
30939
31514
|
|
|
30940
|
-
showTrack(
|
|
30941
|
-
let
|
|
30942
|
-
if (
|
|
30943
|
-
const track = this.tracks[idx];
|
|
31515
|
+
showTrack(trackName) {
|
|
31516
|
+
let track = this.getTrack(trackName);
|
|
31517
|
+
if (track) {
|
|
30944
31518
|
track.visible = true;
|
|
30945
|
-
this.tracks.splice(idx, 1); // Change z-order
|
|
30946
|
-
this.tracks.push(track);
|
|
30947
31519
|
this.render();
|
|
30948
31520
|
} else {
|
|
30949
|
-
console.warn(`No track with name: ${
|
|
31521
|
+
console.warn(`No track with name: ${trackName}`);
|
|
30950
31522
|
}
|
|
30951
31523
|
}
|
|
30952
31524
|
|
|
31525
|
+
// showTrack(trackID) {
|
|
31526
|
+
// let idx = this.tracks.findIndex(t => trackID === t.id)
|
|
31527
|
+
// if (idx >= 0) {
|
|
31528
|
+
// const track = this.tracks[idx]
|
|
31529
|
+
// track.visible = true
|
|
31530
|
+
// this.tracks.splice(idx, 1) // Change z-order
|
|
31531
|
+
// this.tracks.push(track)
|
|
31532
|
+
// this.render()
|
|
31533
|
+
// } else {
|
|
31534
|
+
// console.warn(`No track with name: ${name}`)
|
|
31535
|
+
// }
|
|
31536
|
+
// }
|
|
31537
|
+
|
|
30953
31538
|
// TODO -- remove corresponding row from track panel
|
|
30954
31539
|
deleteTrack(trackID) {
|
|
30955
|
-
let idx = this.tracks.findIndex(t => trackID === t.
|
|
31540
|
+
let idx = this.tracks.findIndex(t => trackID === t.name);
|
|
30956
31541
|
if (idx >= 0) {
|
|
30957
31542
|
this.tracks.splice(idx, 1);
|
|
30958
31543
|
}
|
|
30959
31544
|
this.render();
|
|
30960
31545
|
}
|
|
30961
31546
|
|
|
30962
|
-
getTrack(
|
|
30963
|
-
return this.
|
|
31547
|
+
getTrack(name) {
|
|
31548
|
+
return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.getChordset(name)
|
|
30964
31549
|
}
|
|
30965
31550
|
|
|
30966
|
-
setTrackColor(
|
|
30967
|
-
const t = this.getTrack(
|
|
31551
|
+
setTrackColor(name, color) {
|
|
31552
|
+
const t = this.getTrack(name);
|
|
30968
31553
|
if (t) {
|
|
30969
31554
|
t.color = color;
|
|
30970
31555
|
const trackID = t.id;
|
|
@@ -30991,24 +31576,27 @@ class CircularView {
|
|
|
30991
31576
|
// Remove all children from possible previous renders. React might do this for us when we render, but just in case.
|
|
30992
31577
|
ReactDOM.unmountComponentAtNode(this.container);
|
|
30993
31578
|
|
|
30994
|
-
|
|
31579
|
+
|
|
31580
|
+
|
|
31581
|
+
const visibleChordSets =
|
|
31582
|
+
(this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets).filter(t => t.visible);
|
|
30995
31583
|
|
|
30996
31584
|
const jbrowseTracks = [];
|
|
30997
31585
|
const colors = [];
|
|
30998
31586
|
|
|
30999
|
-
for (let
|
|
31587
|
+
for (let chordSet of visibleChordSets) {
|
|
31588
|
+
|
|
31000
31589
|
jbrowseTracks.push({
|
|
31001
|
-
trackId:
|
|
31002
|
-
name:
|
|
31590
|
+
trackId: chordSet.id,
|
|
31591
|
+
name: chordSet.name,
|
|
31003
31592
|
assemblyNames: ['forIGV'],
|
|
31004
31593
|
type: 'VariantTrack',
|
|
31005
31594
|
adapter: {
|
|
31006
31595
|
type: 'FromConfigAdapter',
|
|
31007
|
-
features:
|
|
31596
|
+
features: chordSet.chords,
|
|
31008
31597
|
}
|
|
31009
31598
|
});
|
|
31010
|
-
colors.push(
|
|
31011
|
-
|
|
31599
|
+
colors.push(chordSet.color);
|
|
31012
31600
|
}
|
|
31013
31601
|
|
|
31014
31602
|
this.viewState = createViewState({
|
|
@@ -31017,7 +31605,7 @@ class CircularView {
|
|
|
31017
31605
|
});
|
|
31018
31606
|
|
|
31019
31607
|
// Set view colors
|
|
31020
|
-
for (let i = 0; i <
|
|
31608
|
+
for (let i = 0; i < visibleChordSets.length; i++) {
|
|
31021
31609
|
this.viewState.config.tracks[i].displays[0].renderer.strokeColor.set(colors[i]);
|
|
31022
31610
|
//this.viewState.config.tracks[i].displays[0].renderer.strokeColor.set("jexl:get(feature, 'color') || 'black'");
|
|
31023
31611
|
//this.viewState.config.tracks[i].displays[0].renderer.strokeColorSelected.set("jexl:get(feature, 'highlightColor') || 'red'");
|
|
@@ -31028,10 +31616,11 @@ class CircularView {
|
|
|
31028
31616
|
|
|
31029
31617
|
ReactDOM.render(this.element, this.container);
|
|
31030
31618
|
|
|
31031
|
-
|
|
31619
|
+
const onChordClick = this.config.onChordClick || defaultOnChordClick;
|
|
31620
|
+
for (let i = 0; i < visibleChordSets.length; i++) {
|
|
31032
31621
|
this.viewState.session.view.showTrack(this.viewState.config.tracks[i].trackId);
|
|
31033
|
-
if (
|
|
31034
|
-
this.viewState.pluginManager.jexl.addFunction('onChordClick',
|
|
31622
|
+
if (onChordClick) {
|
|
31623
|
+
this.viewState.pluginManager.jexl.addFunction('onChordClick', onChordClick);
|
|
31035
31624
|
this.viewState.config.tracks[i].displays[0].onChordClick.set(
|
|
31036
31625
|
'jexl:onChordClick(feature, track, pluginManager)'
|
|
31037
31626
|
);
|
|
@@ -31042,20 +31631,32 @@ class CircularView {
|
|
|
31042
31631
|
|
|
31043
31632
|
function setAlpha(rgba, alpha) {
|
|
31044
31633
|
const [a, b, c, ignore] = rgba.split(','); // rgba(r g b alpha)
|
|
31045
|
-
return `${
|
|
31634
|
+
return `${a},${b},${c},${alpha})`
|
|
31635
|
+
}
|
|
31636
|
+
|
|
31637
|
+
function getAlpha(rgba) {
|
|
31638
|
+
if (rgba.startsWith("rgba(")) {
|
|
31639
|
+
return Number(rgba.split(',')[3].replace(')', ''))
|
|
31640
|
+
} else {
|
|
31641
|
+
return 1
|
|
31642
|
+
}
|
|
31046
31643
|
}
|
|
31047
31644
|
|
|
31048
31645
|
function shortChrName$1(chrName) {
|
|
31049
31646
|
return chrName.startsWith("chr") ? chrName.substring(3) : chrName
|
|
31050
31647
|
}
|
|
31051
31648
|
|
|
31649
|
+
function defaultOnChordClick(feature, chordTrack, pluginManager) {
|
|
31650
|
+
console.log(feature);
|
|
31651
|
+
}
|
|
31652
|
+
|
|
31052
31653
|
function guid() {
|
|
31053
31654
|
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
|
|
31054
31655
|
}
|
|
31055
31656
|
|
|
31056
31657
|
function embedCSS$1() {
|
|
31057
31658
|
|
|
31058
|
-
const css = '.igv-circview-container {\n z-index: 2048;\n position: absolute;\n width: fit-content;\n height: fit-content;\n box-sizing: content-box;\n color: dimgray;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n background-color: white;\n border-color: dimgray;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start
|
|
31659
|
+
const css = '.igv-circview-container {\n z-index: 2048;\n position: absolute;\n width: fit-content;\n height: fit-content;\n box-sizing: content-box;\n color: dimgray;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n background-color: white;\n border-color: dimgray;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-circview-toolbar {\n position: relative;\n width: 100%;\n height: 32px;\n background-color: lightgrey;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n\n.igv-circview-toolbar-button-container {\n height: 100%;\n width: fit-content;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-toolbar-button-container > div {\n margin: 4px;\n}\n\n.igv-circview-track-panel {\n z-index: 1024;\n position: absolute;\n top: 33px;\n left: 0;\n width: 100%;\n height: fit-content;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n.igv-circview-track-panel > div {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-track-panel > div > div {\n margin: 4px;\n}\n\n.igv-circview-swatch-button {\n cursor: pointer;\n padding: 5px;\n width: 8px;\n height: 8px;\n border: 1px solid #8d8b8b;\n border-radius: 16px;\n}\n\n.igv-circview-button {\n cursor: pointer;\n padding: 5px;\n color: #444;\n vertical-align: middle;\n text-align: center;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n border: 1px solid #8d8b8b;\n border-radius: 4px;\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.2);\n}\n\n.igv-circview-button:hover {\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n.igv-circview-button:active {\n color: #007bff;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n/*# sourceMappingURL=circular-view.css.map */\n';
|
|
31059
31660
|
|
|
31060
31661
|
const style = document.createElement('style');
|
|
31061
31662
|
style.setAttribute('type', 'text/css');
|
|
@@ -32417,59 +33018,61 @@ class AlignmentTrack {
|
|
|
32417
33018
|
list.push('<hr/>');
|
|
32418
33019
|
|
|
32419
33020
|
const clickedObject = this.getClickedObject(clickState);
|
|
33021
|
+
|
|
32420
33022
|
if (clickedObject) {
|
|
32421
33023
|
|
|
32422
33024
|
const showSoftClips = this.parent.showSoftClips;
|
|
32423
33025
|
const clickedAlignment = (typeof clickedObject.alignmentContaining === 'function') ?
|
|
32424
33026
|
clickedObject.alignmentContaining(clickState.genomicLocation, showSoftClips) :
|
|
32425
33027
|
clickedObject;
|
|
32426
|
-
|
|
32427
|
-
|
|
32428
|
-
|
|
32429
|
-
|
|
32430
|
-
|
|
32431
|
-
|
|
32432
|
-
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
|
|
33028
|
+
if (clickedAlignment) {
|
|
33029
|
+
if (clickedAlignment.isPaired() && clickedAlignment.isMateMapped()) {
|
|
33030
|
+
list.push({
|
|
33031
|
+
label: 'View mate in split screen',
|
|
33032
|
+
click: () => {
|
|
33033
|
+
if (clickedAlignment.mate) {
|
|
33034
|
+
const referenceFrame = clickState.viewport.referenceFrame;
|
|
33035
|
+
if (this.browser.genome.getChromosome(clickedAlignment.mate.chr)) {
|
|
33036
|
+
this.highlightedAlignmentReadNamed = clickedAlignment.readName;
|
|
33037
|
+
this.browser.presentMultiLocusPanel(clickedAlignment, referenceFrame);
|
|
33038
|
+
} else {
|
|
33039
|
+
Alert.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
|
|
33040
|
+
}
|
|
32438
33041
|
}
|
|
32439
|
-
}
|
|
32440
|
-
|
|
32441
|
-
|
|
32442
|
-
});
|
|
32443
|
-
}
|
|
32444
|
-
|
|
32445
|
-
list.push({
|
|
32446
|
-
label: 'View read sequence',
|
|
32447
|
-
click: () => {
|
|
32448
|
-
const alignment = clickedAlignment;
|
|
32449
|
-
if (!alignment) return
|
|
32450
|
-
|
|
32451
|
-
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
32452
|
-
if (!seqstring || "*" === seqstring) {
|
|
32453
|
-
Alert.presentAlert("Read sequence: *");
|
|
32454
|
-
} else {
|
|
32455
|
-
Alert.presentAlert(seqstring);
|
|
32456
|
-
}
|
|
33042
|
+
},
|
|
33043
|
+
init: undefined
|
|
33044
|
+
});
|
|
32457
33045
|
}
|
|
32458
|
-
});
|
|
32459
33046
|
|
|
32460
|
-
if (isSecureContext()) {
|
|
32461
33047
|
list.push({
|
|
32462
|
-
label: '
|
|
33048
|
+
label: 'View read sequence',
|
|
32463
33049
|
click: () => {
|
|
32464
33050
|
const alignment = clickedAlignment;
|
|
32465
33051
|
if (!alignment) return
|
|
33052
|
+
|
|
32466
33053
|
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
32467
|
-
|
|
33054
|
+
if (!seqstring || "*" === seqstring) {
|
|
33055
|
+
Alert.presentAlert("Read sequence: *");
|
|
33056
|
+
} else {
|
|
33057
|
+
Alert.presentAlert(seqstring);
|
|
33058
|
+
}
|
|
32468
33059
|
}
|
|
32469
33060
|
});
|
|
32470
|
-
}
|
|
32471
33061
|
|
|
32472
|
-
|
|
33062
|
+
if (isSecureContext()) {
|
|
33063
|
+
list.push({
|
|
33064
|
+
label: 'Copy read sequence',
|
|
33065
|
+
click: () => {
|
|
33066
|
+
const alignment = clickedAlignment;
|
|
33067
|
+
if (!alignment) return
|
|
33068
|
+
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
33069
|
+
navigator.clipboard.writeText(seqstring);
|
|
33070
|
+
}
|
|
33071
|
+
});
|
|
33072
|
+
}
|
|
33073
|
+
|
|
33074
|
+
list.push('<hr/>');
|
|
33075
|
+
}
|
|
32473
33076
|
}
|
|
32474
33077
|
|
|
32475
33078
|
// Experimental JBrowse feature
|
|
@@ -32739,7 +33342,7 @@ function getChrColor(chr) {
|
|
|
32739
33342
|
chrColorMap[chr] = color;
|
|
32740
33343
|
return color
|
|
32741
33344
|
} else {
|
|
32742
|
-
const color = IGVColor.randomRGB();
|
|
33345
|
+
const color = IGVColor.randomRGB(0, 255);
|
|
32743
33346
|
chrColorMap[chr] = color;
|
|
32744
33347
|
return color
|
|
32745
33348
|
}
|
|
@@ -32747,7 +33350,7 @@ function getChrColor(chr) {
|
|
|
32747
33350
|
|
|
32748
33351
|
const chrColorMap = {
|
|
32749
33352
|
"chrX": "rgb(204, 153, 0)",
|
|
32750
|
-
"chrY": "rgb(153, 204, 0",
|
|
33353
|
+
"chrY": "rgb(153, 204, 0)",
|
|
32751
33354
|
"chrUn": "rgb(50, 50, 50)",
|
|
32752
33355
|
"chr1": "rgb(80, 80, 255)",
|
|
32753
33356
|
"chrI": "rgb(139, 155, 187)",
|
|
@@ -33001,143 +33604,68 @@ class RulerViewport extends TrackViewport {
|
|
|
33001
33604
|
|
|
33002
33605
|
}
|
|
33003
33606
|
|
|
33004
|
-
|
|
33005
|
-
|
|
33006
|
-
|
|
33007
|
-
* Copyright (c) 2014 Broad Institute
|
|
33008
|
-
*
|
|
33009
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33010
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
33011
|
-
* in the Software without restriction, including without limitation the rights
|
|
33012
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
33013
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
33014
|
-
* furnished to do so, subject to the following conditions:
|
|
33015
|
-
*
|
|
33016
|
-
* The above copyright notice and this permission notice shall be included in
|
|
33017
|
-
* all copies or substantial portions of the Software.
|
|
33018
|
-
*
|
|
33019
|
-
*
|
|
33020
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33021
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33022
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
33023
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33024
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33025
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
33026
|
-
* THE SOFTWARE.
|
|
33027
|
-
*/
|
|
33028
|
-
|
|
33029
|
-
class IdeogramViewport extends TrackViewport {
|
|
33030
|
-
|
|
33031
|
-
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
33032
|
-
super(trackView, viewportColumn, referenceFrame, width);
|
|
33033
|
-
}
|
|
33034
|
-
|
|
33035
|
-
initializationHelper() {
|
|
33036
|
-
|
|
33037
|
-
this.$ideogramCanvas = $$1('<canvas>', {class: 'igv-ideogram-canvas'});
|
|
33038
|
-
this.$ideogramCanvas.insertBefore(this.$canvas);
|
|
33039
|
-
|
|
33040
|
-
const canvas = this.$ideogramCanvas.get(0);
|
|
33041
|
-
this.ideogram_ctx = canvas.getContext('2d');
|
|
33042
|
-
|
|
33043
|
-
this.$canvas.remove();
|
|
33044
|
-
this.canvas = undefined;
|
|
33045
|
-
this.ctx = undefined;
|
|
33046
|
-
|
|
33047
|
-
this.addMouseHandlers();
|
|
33048
|
-
|
|
33049
|
-
}
|
|
33050
|
-
|
|
33051
|
-
addMouseHandlers() {
|
|
33052
|
-
this.addViewportClickHandler(this.$viewport.get(0));
|
|
33053
|
-
}
|
|
33054
|
-
|
|
33055
|
-
removeMouseHandlers() {
|
|
33056
|
-
this.removeViewportClickHandler(this.$viewport.get(0));
|
|
33057
|
-
|
|
33058
|
-
}
|
|
33059
|
-
|
|
33060
|
-
addViewportClickHandler(viewport) {
|
|
33061
|
-
|
|
33062
|
-
this.boundClickHandler = clickHandler.bind(this);
|
|
33063
|
-
viewport.addEventListener('click', this.boundClickHandler);
|
|
33064
|
-
|
|
33065
|
-
function clickHandler(event) {
|
|
33066
|
-
|
|
33067
|
-
const {xNormalized, width} = translateMouseCoordinates$1(event, this.ideogram_ctx.canvas);
|
|
33068
|
-
const {bpLength} = this.browser.genome.getChromosome(this.referenceFrame.chr);
|
|
33069
|
-
const locusLength = this.referenceFrame.bpPerPixel * width;
|
|
33070
|
-
const chrCoveragePercentage = locusLength / bpLength;
|
|
33071
|
-
|
|
33072
|
-
let xPercentage = xNormalized;
|
|
33073
|
-
if (xPercentage - (chrCoveragePercentage / 2.0) < 0) {
|
|
33074
|
-
xPercentage = chrCoveragePercentage / 2.0;
|
|
33075
|
-
}
|
|
33607
|
+
const viewportColumnManager =
|
|
33608
|
+
{
|
|
33609
|
+
createColumns: (columnContainer, count) => {
|
|
33076
33610
|
|
|
33077
|
-
|
|
33078
|
-
|
|
33611
|
+
for (let i = 0; i < count; i++) {
|
|
33612
|
+
if (0 === i) {
|
|
33613
|
+
createColumn(columnContainer, 'igv-column');
|
|
33614
|
+
} else {
|
|
33615
|
+
columnContainer.appendChild(div$1({class: 'igv-column-shim'}));
|
|
33616
|
+
createColumn(columnContainer, 'igv-column');
|
|
33617
|
+
}
|
|
33079
33618
|
}
|
|
33080
33619
|
|
|
33081
|
-
|
|
33082
|
-
const ee = Math.round((xPercentage + (chrCoveragePercentage / 2.0)) * bpLength);
|
|
33083
|
-
|
|
33084
|
-
this.referenceFrame.start = ss;
|
|
33085
|
-
this.referenceFrame.end = ee;
|
|
33086
|
-
this.referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
33087
|
-
|
|
33088
|
-
this.browser.updateViews(this.referenceFrame, this.browser.trackViews, true);
|
|
33089
|
-
|
|
33090
|
-
}
|
|
33620
|
+
},
|
|
33091
33621
|
|
|
33092
|
-
|
|
33622
|
+
removeColumnAtIndex: (i, column) => {
|
|
33623
|
+
const shim = 0 === i ? column.nextElementSibling : column.previousElementSibling;
|
|
33624
|
+
column.remove();
|
|
33625
|
+
shim.remove();
|
|
33626
|
+
},
|
|
33093
33627
|
|
|
33094
|
-
|
|
33095
|
-
viewport.removeEventListener('click', this.boundClickHandler);
|
|
33096
|
-
}
|
|
33628
|
+
insertAfter: referenceElement => {
|
|
33097
33629
|
|
|
33098
|
-
|
|
33099
|
-
|
|
33100
|
-
}
|
|
33630
|
+
const shim = div$1({class: 'igv-column-shim'});
|
|
33631
|
+
insertElementAfter(shim, referenceElement);
|
|
33101
33632
|
|
|
33102
|
-
|
|
33633
|
+
const column = div$1({class: 'igv-column'});
|
|
33634
|
+
insertElementAfter(column, shim);
|
|
33103
33635
|
|
|
33104
|
-
|
|
33636
|
+
return column
|
|
33637
|
+
},
|
|
33105
33638
|
|
|
33106
|
-
|
|
33107
|
-
context,
|
|
33108
|
-
referenceFrame: this.referenceFrame,
|
|
33109
|
-
pixelWidth: width,
|
|
33110
|
-
pixelHeight: height
|
|
33111
|
-
});
|
|
33639
|
+
insertBefore: (referenceElement, count) => {
|
|
33112
33640
|
|
|
33113
|
-
|
|
33114
|
-
}
|
|
33641
|
+
for (let i = 0; i < count; i++) {
|
|
33115
33642
|
|
|
33116
|
-
|
|
33117
|
-
|
|
33118
|
-
}
|
|
33643
|
+
const column = div$1({class: 'igv-column'});
|
|
33644
|
+
insertElementBefore(column, referenceElement);
|
|
33119
33645
|
|
|
33120
|
-
|
|
33646
|
+
if (count > 1 && i > 0) {
|
|
33647
|
+
const columnShim = div$1({class: 'igv-column-shim'});
|
|
33648
|
+
insertElementBefore(columnShim, column);
|
|
33649
|
+
}
|
|
33121
33650
|
|
|
33122
|
-
|
|
33651
|
+
}
|
|
33123
33652
|
|
|
33124
|
-
|
|
33653
|
+
},
|
|
33125
33654
|
|
|
33126
|
-
|
|
33127
|
-
context: this.ideogram_ctx,
|
|
33128
|
-
referenceFrame,
|
|
33129
|
-
pixelWidth: this.$viewport.width(),
|
|
33130
|
-
pixelHeight: this.$viewport.height()
|
|
33131
|
-
});
|
|
33132
|
-
}
|
|
33655
|
+
indexOfColumn: (columnContainer, column) => {
|
|
33133
33656
|
|
|
33134
|
-
|
|
33135
|
-
}
|
|
33657
|
+
const allColumns = columnContainer.querySelectorAll('.igv-column');
|
|
33136
33658
|
|
|
33137
|
-
|
|
33138
|
-
|
|
33659
|
+
for (let i = 0; i < allColumns.length; i++) {
|
|
33660
|
+
const c = allColumns[ i ];
|
|
33661
|
+
if (c === column) {
|
|
33662
|
+
return i
|
|
33663
|
+
}
|
|
33664
|
+
}
|
|
33139
33665
|
|
|
33140
|
-
|
|
33666
|
+
return undefined
|
|
33667
|
+
},
|
|
33668
|
+
};
|
|
33141
33669
|
|
|
33142
33670
|
/*
|
|
33143
33671
|
* The MIT License (MIT)
|
|
@@ -33164,185 +33692,157 @@ class IdeogramViewport extends TrackViewport {
|
|
|
33164
33692
|
* THE SOFTWARE.
|
|
33165
33693
|
*/
|
|
33166
33694
|
|
|
33167
|
-
|
|
33168
|
-
* Test if the given value is a string or number. Not using typeof as it fails on boxed primitives.
|
|
33169
|
-
*
|
|
33170
|
-
* @param value
|
|
33171
|
-
* @returns boolean
|
|
33172
|
-
*/
|
|
33695
|
+
class IdeogramViewport extends TrackViewport {
|
|
33173
33696
|
|
|
33174
|
-
|
|
33175
|
-
|
|
33176
|
-
|
|
33177
|
-
return (value !== undefined && (simpleTypes.has(valueType) || value.substring || value.toFixed))
|
|
33178
|
-
}
|
|
33697
|
+
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
33698
|
+
super(trackView, viewportColumn, referenceFrame, width);
|
|
33699
|
+
}
|
|
33179
33700
|
|
|
33180
|
-
|
|
33701
|
+
initializationHelper() {
|
|
33181
33702
|
|
|
33182
|
-
|
|
33183
|
-
|
|
33184
|
-
headers: config.headers,
|
|
33185
|
-
withCredentials: config.withCredentials,
|
|
33186
|
-
filename: config.filename
|
|
33187
|
-
};
|
|
33703
|
+
this.$ideogramCanvas = $$1('<canvas>', {class: 'igv-ideogram-canvas'});
|
|
33704
|
+
this.$ideogramCanvas.insertBefore(this.$canvas);
|
|
33188
33705
|
|
|
33189
|
-
|
|
33190
|
-
|
|
33706
|
+
const canvas = this.$ideogramCanvas.get(0);
|
|
33707
|
+
this.ideogram_ctx = canvas.getContext('2d');
|
|
33191
33708
|
|
|
33192
|
-
|
|
33193
|
-
|
|
33194
|
-
|
|
33195
|
-
* @returns {boolean}
|
|
33196
|
-
*/
|
|
33709
|
+
this.$canvas.remove();
|
|
33710
|
+
this.canvas = undefined;
|
|
33711
|
+
this.ctx = undefined;
|
|
33197
33712
|
|
|
33198
|
-
|
|
33199
|
-
//
|
|
33200
|
-
// const a = (navigator.userAgent || navigator.vendor || window.opera);
|
|
33201
|
-
// return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) ||
|
|
33202
|
-
// /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4)))
|
|
33203
|
-
//
|
|
33204
|
-
// }
|
|
33713
|
+
this.addMouseHandlers();
|
|
33205
33714
|
|
|
33206
|
-
|
|
33207
|
-
var min, max;
|
|
33715
|
+
}
|
|
33208
33716
|
|
|
33209
|
-
|
|
33210
|
-
|
|
33211
|
-
|
|
33717
|
+
addMouseHandlers() {
|
|
33718
|
+
this.addBrowserObserver();
|
|
33719
|
+
this.addViewportClickHandler(this.$viewport.get(0));
|
|
33720
|
+
}
|
|
33212
33721
|
|
|
33213
|
-
|
|
33214
|
-
|
|
33215
|
-
|
|
33216
|
-
|
|
33722
|
+
removeMouseHandlers() {
|
|
33723
|
+
this.removeBrowserObserver();
|
|
33724
|
+
this.removeViewportClickHandler(this.$viewport.get(0));
|
|
33725
|
+
|
|
33726
|
+
}
|
|
33727
|
+
|
|
33728
|
+
addBrowserObserver() {
|
|
33729
|
+
|
|
33730
|
+
function observerHandler(referenceFrameList) {
|
|
33731
|
+
const column = this.$viewport.get(0).parentElement;
|
|
33732
|
+
if (null !== column) {
|
|
33733
|
+
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column);
|
|
33734
|
+
// console.log(`ideogram-viewport - locus-change-handler index(${ index }) ${ referenceFrameList[ index ].getLocusString() } ${ Date.now() } `)
|
|
33735
|
+
this.update(this.ideogram_ctx, this.$viewport.width(), this.$viewport.height(), referenceFrameList[ index ]);
|
|
33217
33736
|
}
|
|
33218
|
-
}
|
|
33737
|
+
}
|
|
33219
33738
|
|
|
33220
|
-
|
|
33221
|
-
|
|
33222
|
-
if (max < 0) max = 0;
|
|
33223
|
-
} else {
|
|
33224
|
-
// No features -- default
|
|
33225
|
-
min = 0;
|
|
33226
|
-
max = 100;
|
|
33739
|
+
this.boundObserverHandler = observerHandler.bind(this);
|
|
33740
|
+
this.browser.on('locuschange', this.boundObserverHandler);
|
|
33227
33741
|
}
|
|
33228
33742
|
|
|
33229
|
-
|
|
33230
|
-
|
|
33743
|
+
removeBrowserObserver() {
|
|
33744
|
+
this.browser.off('locuschange', this.boundObserverHandler);
|
|
33745
|
+
}
|
|
33231
33746
|
|
|
33232
|
-
|
|
33747
|
+
addViewportClickHandler(viewport) {
|
|
33233
33748
|
|
|
33234
|
-
|
|
33235
|
-
let ee = extent.end;
|
|
33749
|
+
function clickHandler(event) {
|
|
33236
33750
|
|
|
33237
|
-
|
|
33751
|
+
const column = viewport.parentElement;
|
|
33752
|
+
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column);
|
|
33753
|
+
const referenceFrame = this.browser.referenceFrameList[ index ];
|
|
33238
33754
|
|
|
33239
|
-
|
|
33240
|
-
|
|
33755
|
+
const {xNormalized, width} = translateMouseCoordinates$1(event, this.ideogram_ctx.canvas);
|
|
33756
|
+
const {bpLength} = this.browser.genome.getChromosome(referenceFrame.chr);
|
|
33757
|
+
const locusLength = referenceFrame.bpPerPixel * width;
|
|
33758
|
+
const chrCoveragePercentage = locusLength / bpLength;
|
|
33241
33759
|
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
|
|
33245
|
-
|
|
33246
|
-
ss = 0;
|
|
33247
|
-
ee = minimumBP;
|
|
33248
|
-
}
|
|
33760
|
+
let xPercentage = xNormalized;
|
|
33761
|
+
if (xPercentage - (chrCoveragePercentage / 2.0) < 0) {
|
|
33762
|
+
xPercentage = chrCoveragePercentage / 2.0;
|
|
33763
|
+
}
|
|
33249
33764
|
|
|
33250
|
-
|
|
33765
|
+
if (xPercentage + (chrCoveragePercentage / 2.0) > 1.0) {
|
|
33766
|
+
xPercentage = 1.0 - chrCoveragePercentage / 2.0;
|
|
33767
|
+
}
|
|
33251
33768
|
|
|
33252
|
-
|
|
33769
|
+
const ss = Math.round((xPercentage - (chrCoveragePercentage / 2.0)) * bpLength);
|
|
33770
|
+
const ee = Math.round((xPercentage + (chrCoveragePercentage / 2.0)) * bpLength);
|
|
33253
33771
|
|
|
33254
|
-
|
|
33255
|
-
|
|
33256
|
-
|
|
33257
|
-
} else if (center + minimumBP / 2 > chromosomeLengthBP) {
|
|
33258
|
-
ee = chromosomeLengthBP;
|
|
33259
|
-
ss = ee - minimumBP;
|
|
33260
|
-
} else {
|
|
33261
|
-
ss = center - minimumBP / 2;
|
|
33262
|
-
ee = ss + minimumBP;
|
|
33263
|
-
}
|
|
33264
|
-
}
|
|
33772
|
+
referenceFrame.start = ss;
|
|
33773
|
+
referenceFrame.end = ee;
|
|
33774
|
+
referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
33265
33775
|
|
|
33266
|
-
|
|
33267
|
-
extent.end = Math.floor(ee);
|
|
33268
|
-
};
|
|
33776
|
+
this.browser.updateViews(referenceFrame, this.browser.trackViews, true);
|
|
33269
33777
|
|
|
33270
|
-
|
|
33271
|
-
|
|
33272
|
-
|
|
33273
|
-
|
|
33274
|
-
* Released under the MIT License.
|
|
33275
|
-
*/
|
|
33778
|
+
}
|
|
33779
|
+
|
|
33780
|
+
this.boundClickHandler = clickHandler.bind(this);
|
|
33781
|
+
viewport.addEventListener('click', this.boundClickHandler);
|
|
33276
33782
|
|
|
33277
|
-
const isNumber = function (num) {
|
|
33278
|
-
if (typeof num === 'number') {
|
|
33279
|
-
return num - num === 0
|
|
33280
|
-
}
|
|
33281
|
-
if (typeof num === 'string' && num.trim() !== '') {
|
|
33282
|
-
return Number.isFinite ? Number.isFinite(+num) : isFinite(+num)
|
|
33283
33783
|
}
|
|
33284
|
-
return false
|
|
33285
|
-
};
|
|
33286
33784
|
|
|
33287
|
-
|
|
33288
|
-
|
|
33289
|
-
// This will fail if Google API key is not defined
|
|
33290
|
-
if (getApiKey() === undefined) {
|
|
33291
|
-
throw Error("Google drive is referenced, but API key is not defined. An API key is required for Google Drive access")
|
|
33292
|
-
}
|
|
33293
|
-
const json = await getDriveFileInfo(url);
|
|
33294
|
-
return json.originalFileName || json.name
|
|
33295
|
-
} else {
|
|
33296
|
-
return getFilename$1(url)
|
|
33785
|
+
removeViewportClickHandler(viewport) {
|
|
33786
|
+
viewport.removeEventListener('click', this.boundClickHandler);
|
|
33297
33787
|
}
|
|
33298
|
-
}
|
|
33299
33788
|
|
|
33300
|
-
|
|
33789
|
+
setWidth(width) {
|
|
33790
|
+
this.$viewport.width(width);
|
|
33791
|
+
}
|
|
33301
33792
|
|
|
33302
|
-
|
|
33303
|
-
units,
|
|
33304
|
-
value,
|
|
33305
|
-
floored;
|
|
33793
|
+
drawSVGWithContext(context, width, height, id, x, y, yClipOffset) {
|
|
33306
33794
|
|
|
33307
|
-
|
|
33308
|
-
denom = 1e6;
|
|
33309
|
-
units = " mb";
|
|
33310
|
-
} else if (raw > 1e4) {
|
|
33795
|
+
context.saveWithTranslationAndClipRect(id, x, y, width, height, yClipOffset);
|
|
33311
33796
|
|
|
33312
|
-
|
|
33313
|
-
|
|
33797
|
+
this.trackView.track.draw({
|
|
33798
|
+
context,
|
|
33799
|
+
referenceFrame: this.referenceFrame,
|
|
33800
|
+
pixelWidth: width,
|
|
33801
|
+
pixelHeight: height
|
|
33802
|
+
});
|
|
33314
33803
|
|
|
33315
|
-
|
|
33316
|
-
floored = Math.floor(value);
|
|
33317
|
-
return numberFormatter$1(floored) + units
|
|
33318
|
-
} else {
|
|
33319
|
-
return numberFormatter$1(raw) + " bp"
|
|
33804
|
+
context.restore();
|
|
33320
33805
|
}
|
|
33321
33806
|
|
|
33322
|
-
|
|
33323
|
-
|
|
33324
|
-
|
|
33325
|
-
|
|
33326
|
-
}
|
|
33807
|
+
update(context, pixelWidth, pixelHeight, referenceFrame) {
|
|
33808
|
+
this.$canvas.hide();
|
|
33809
|
+
IGVGraphics.configureHighDPICanvas(context, pixelWidth, pixelHeight);
|
|
33810
|
+
this.trackView.track.draw({ context, referenceFrame, pixelWidth, pixelHeight });
|
|
33811
|
+
}
|
|
33327
33812
|
|
|
33813
|
+
startSpinner() {
|
|
33814
|
+
}
|
|
33328
33815
|
|
|
33329
|
-
|
|
33330
|
-
|
|
33331
|
-
}
|
|
33816
|
+
stopSpinner() {
|
|
33817
|
+
}
|
|
33332
33818
|
|
|
33333
|
-
function createColumn(columnContainer, className) {
|
|
33334
|
-
const column = div$1({class: className});
|
|
33335
|
-
columnContainer.appendChild(column);
|
|
33336
33819
|
}
|
|
33337
33820
|
|
|
33821
|
+
/*
|
|
33822
|
+
* The MIT License (MIT)
|
|
33823
|
+
*
|
|
33824
|
+
* Copyright (c) 2014 Broad Institute
|
|
33825
|
+
*
|
|
33826
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33827
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
33828
|
+
* in the Software without restriction, including without limitation the rights
|
|
33829
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
33830
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
33831
|
+
* furnished to do so, subject to the following conditions:
|
|
33832
|
+
*
|
|
33833
|
+
* The above copyright notice and this permission notice shall be included in
|
|
33834
|
+
* all copies or substantial portions of the Software.
|
|
33835
|
+
*
|
|
33836
|
+
*
|
|
33837
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33838
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33839
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
33840
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33841
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33842
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
33843
|
+
* THE SOFTWARE.
|
|
33844
|
+
*/
|
|
33338
33845
|
|
|
33339
|
-
function insertElementBefore(element, referenceNode) {
|
|
33340
|
-
referenceNode.parentNode.insertBefore(element, referenceNode);
|
|
33341
|
-
}
|
|
33342
|
-
|
|
33343
|
-
function insertElementAfter(element, referenceNode) {
|
|
33344
|
-
referenceNode.parentNode.insertBefore(element, referenceNode.nextSibling);
|
|
33345
|
-
}
|
|
33346
33846
|
|
|
33347
33847
|
function createViewport(trackView, column, referenceFrame, width) {
|
|
33348
33848
|
|
|
@@ -33355,13 +33855,6 @@ function createViewport(trackView, column, referenceFrame, width) {
|
|
|
33355
33855
|
}
|
|
33356
33856
|
}
|
|
33357
33857
|
|
|
33358
|
-
/**
|
|
33359
|
-
* Test to see if page is loaded in a secure context, that is by https or is localhost.
|
|
33360
|
-
*/
|
|
33361
|
-
function isSecureContext() {
|
|
33362
|
-
return window.location.protocol === "https:" || window.location.hostname === "localhost"
|
|
33363
|
-
}
|
|
33364
|
-
|
|
33365
33858
|
const maxFontSize = 10;
|
|
33366
33859
|
|
|
33367
33860
|
const fontConfigureTemplate =
|
|
@@ -33377,7 +33870,7 @@ class SampleNameViewport {
|
|
|
33377
33870
|
|
|
33378
33871
|
constructor(trackView, column, unused, width) {
|
|
33379
33872
|
|
|
33380
|
-
this.guid = guid$
|
|
33873
|
+
this.guid = guid$2();
|
|
33381
33874
|
this.trackView = trackView;
|
|
33382
33875
|
|
|
33383
33876
|
this.browser = trackView.browser;
|
|
@@ -33495,7 +33988,7 @@ class SampleNameViewport {
|
|
|
33495
33988
|
const {width, height} = this.viewport.getBoundingClientRect();
|
|
33496
33989
|
|
|
33497
33990
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
33498
|
-
const id = `${str}_sample_names_guid_${guid$
|
|
33991
|
+
const id = `${str}_sample_names_guid_${guid$2()}`;
|
|
33499
33992
|
|
|
33500
33993
|
context.saveWithTranslationAndClipRect(id, deltaX, deltaY + yScrollDelta, width, height, -yScrollDelta);
|
|
33501
33994
|
|
|
@@ -33879,7 +34372,7 @@ class TrackView {
|
|
|
33879
34372
|
|
|
33880
34373
|
constructor(browser, columnContainer, track) {
|
|
33881
34374
|
|
|
33882
|
-
this.namespace = `trackview-${guid$
|
|
34375
|
+
this.namespace = `trackview-${guid$2()}`;
|
|
33883
34376
|
|
|
33884
34377
|
this.browser = browser;
|
|
33885
34378
|
this.track = track;
|
|
@@ -34234,11 +34727,13 @@ class TrackView {
|
|
|
34234
34727
|
for (let viewport of reloadableViewports) {
|
|
34235
34728
|
await viewport.loadFeatures();
|
|
34236
34729
|
}
|
|
34730
|
+
|
|
34731
|
+
if (this.disposed) return // Track was removed during load
|
|
34237
34732
|
|
|
34238
34733
|
// Very special case for variant tracks in multilocus view. The # of rows to allocate to the variant (site)
|
|
34239
34734
|
// section depends on data from all the views. We only need to adjust this however if any data was loaded
|
|
34240
34735
|
// (i.e. reloadableViewports.length > 0)
|
|
34241
|
-
if (typeof this.track.variantRowCount === 'function' && reloadableViewports.length > 0) {
|
|
34736
|
+
if (this.track && typeof this.track.variantRowCount === 'function' && reloadableViewports.length > 0) {
|
|
34242
34737
|
let maxRow = 0;
|
|
34243
34738
|
for (let viewport of this.viewports) {
|
|
34244
34739
|
if (viewport.tile && viewport.tile.features) {
|
|
@@ -34254,7 +34749,6 @@ class TrackView {
|
|
|
34254
34749
|
}
|
|
34255
34750
|
}
|
|
34256
34751
|
|
|
34257
|
-
if (this.disposed) return // Track was removed during load
|
|
34258
34752
|
|
|
34259
34753
|
if (this.track.autoscale) {
|
|
34260
34754
|
let allFeatures = [];
|
|
@@ -34702,7 +35196,7 @@ function renderSVGAxis(context, track, axisCanvas, deltaX, deltaY) {
|
|
|
34702
35196
|
const {y, width, height} = axisCanvas.getBoundingClientRect();
|
|
34703
35197
|
|
|
34704
35198
|
const str = (track.name || track.id).replace(/\W/g, '');
|
|
34705
|
-
const id = `${str}_axis_guid_${guid$
|
|
35199
|
+
const id = `${str}_axis_guid_${guid$2()}`;
|
|
34706
35200
|
|
|
34707
35201
|
context.saveWithTranslationAndClipRect(id, deltaX, y + deltaY, width, height, 0);
|
|
34708
35202
|
|
|
@@ -34982,6 +35476,9 @@ class GFFFeature {
|
|
|
34982
35476
|
|
|
34983
35477
|
pd.push({name: 'Type', value: this.type});
|
|
34984
35478
|
pd.push({name: 'Source', value: this.source});
|
|
35479
|
+
if (this.score !== undefined) {
|
|
35480
|
+
pd.push({name: 'Score', value: this.score});
|
|
35481
|
+
}
|
|
34985
35482
|
|
|
34986
35483
|
if (this.attributeString) {
|
|
34987
35484
|
const atts = parseAttributeString(this.attributeString, this.delim);
|
|
@@ -35230,7 +35727,7 @@ function decode(tokens, header) {
|
|
|
35230
35727
|
chr: tokens[0],
|
|
35231
35728
|
start: parseInt(tokens[3]) - 1,
|
|
35232
35729
|
end: parseInt(tokens[4]),
|
|
35233
|
-
score: "." === tokens[5] ?
|
|
35730
|
+
score: "." === tokens[5] ? undefined : Number(tokens[5]),
|
|
35234
35731
|
strand: tokens[6],
|
|
35235
35732
|
phase: "." === tokens[7] ? 0 : parseInt(tokens[7]),
|
|
35236
35733
|
attributeString: tokens[8],
|
|
@@ -36586,244 +37083,29 @@ class SegFeature {
|
|
|
36586
37083
|
* THE SOFTWARE.
|
|
36587
37084
|
*/
|
|
36588
37085
|
|
|
36589
|
-
|
|
36590
|
-
|
|
36591
|
-
|
|
37086
|
+
/**
|
|
37087
|
+
* Create a variant from an array of tokens representing a line in a "VCF" file
|
|
37088
|
+
* @param tokens
|
|
37089
|
+
*/
|
|
36592
37090
|
function createVCFVariant(tokens) {
|
|
36593
|
-
|
|
36594
|
-
|
|
36595
|
-
|
|
36596
|
-
|
|
36597
|
-
|
|
36598
|
-
|
|
36599
|
-
|
|
36600
|
-
|
|
36601
|
-
|
|
36602
|
-
|
|
36603
|
-
this.referenceBases = tokens[3];
|
|
36604
|
-
this.alternateBases = tokens[4];
|
|
36605
|
-
this.quality = tokens[5];
|
|
36606
|
-
this.filter = tokens[6];
|
|
36607
|
-
this.info = getInfoObject(tokens[7]);
|
|
36608
|
-
this.init();
|
|
36609
|
-
}
|
|
36610
|
-
|
|
36611
|
-
init() {
|
|
36612
|
-
|
|
36613
|
-
const ref = this.referenceBases;
|
|
36614
|
-
const altBases = this.alternateBases;
|
|
36615
|
-
|
|
36616
|
-
if (this.info) {
|
|
36617
|
-
if (this.info["VT"]) {
|
|
36618
|
-
this.type = this.info["VT"];
|
|
36619
|
-
} else if (this.info["SVTYPE"]) {
|
|
36620
|
-
this.type = "SV";
|
|
36621
|
-
} else if (this.info["PERIOD"]) {
|
|
36622
|
-
this.type = "STR";
|
|
36623
|
-
}
|
|
36624
|
-
}
|
|
36625
|
-
if (this.type === undefined) {
|
|
36626
|
-
this.type = determineType(ref, altBases);
|
|
36627
|
-
}
|
|
36628
|
-
if (this.type === "NONVARIANT") {
|
|
36629
|
-
this.heterozygosity = 0;
|
|
36630
|
-
}
|
|
36631
|
-
|
|
36632
|
-
// Determine start/end coordinates -- these are the coordinates representing the actual variant,
|
|
36633
|
-
// not the leading or trailing reference
|
|
36634
|
-
if (this.info["END"]) {
|
|
36635
|
-
this.start = this.pos - 1;
|
|
36636
|
-
if (this.info["CHR2"] && this.info["CHR2"] !== this.chr) {
|
|
36637
|
-
this.end = this.start + 1;
|
|
36638
|
-
} else {
|
|
36639
|
-
this.end = Number.parseInt(this.info["END"]);
|
|
36640
|
-
}
|
|
36641
|
-
} else {
|
|
36642
|
-
if (this.type === "NONVARIANT") {
|
|
36643
|
-
this.start = this.pos - 1; // convert to 0-based coordinate convention
|
|
36644
|
-
this.end = this.start + ref.length;
|
|
36645
|
-
} else {
|
|
36646
|
-
|
|
36647
|
-
const altTokens = altBases.split(",").filter(token => token.length > 0);
|
|
36648
|
-
this.alleles = [];
|
|
36649
|
-
this.start = undefined;
|
|
36650
|
-
this.end = undefined;
|
|
36651
|
-
|
|
36652
|
-
for (let alt of altTokens) {
|
|
36653
|
-
|
|
36654
|
-
this.alleles.push(alt);
|
|
36655
|
-
|
|
36656
|
-
// We don't yet handle SV and other special alt representations
|
|
36657
|
-
if ("SV" !== this.type && isKnownAlt(alt)) {
|
|
36658
|
-
|
|
36659
|
-
let altLength = alt.length;
|
|
36660
|
-
let lengthOnRef = ref.length;
|
|
36661
|
-
const lmin = Math.min(altLength, lengthOnRef);
|
|
36662
|
-
|
|
36663
|
-
// Trim off matching bases. Try first match, then right -> left, then any remaining left -> right
|
|
36664
|
-
let s = 0;
|
|
36665
|
-
|
|
36666
|
-
while (s < lmin && (ref.charCodeAt(s) === alt.charCodeAt(s))) {
|
|
36667
|
-
s++;
|
|
36668
|
-
altLength--;
|
|
36669
|
-
lengthOnRef--;
|
|
36670
|
-
}
|
|
36671
|
-
|
|
36672
|
-
// right -> left from end
|
|
36673
|
-
while (altLength > 0 && lengthOnRef > 0) {
|
|
36674
|
-
const altIdx = s + altLength - 1;
|
|
36675
|
-
const refIdx = s + lengthOnRef - 1;
|
|
36676
|
-
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
36677
|
-
altLength--;
|
|
36678
|
-
lengthOnRef--;
|
|
36679
|
-
} else {
|
|
36680
|
-
break
|
|
36681
|
-
}
|
|
36682
|
-
}
|
|
36683
|
-
|
|
36684
|
-
// if any remaining, left -> right
|
|
36685
|
-
while (altLength > 0 && lengthOnRef > 0) {
|
|
36686
|
-
const altIdx = s;
|
|
36687
|
-
const refIdx = s;
|
|
36688
|
-
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
36689
|
-
s++;
|
|
36690
|
-
altLength--;
|
|
36691
|
-
lengthOnRef--;
|
|
36692
|
-
} else {
|
|
36693
|
-
break
|
|
36694
|
-
}
|
|
36695
|
-
}
|
|
36696
|
-
|
|
36697
|
-
const alleleStart = this.pos + s - 1; // -1 for zero based coordinates
|
|
36698
|
-
const alleleEnd = alleleStart + lengthOnRef;
|
|
36699
|
-
this.start = this.start === undefined ? alleleStart : Math.min(this.start, alleleStart);
|
|
36700
|
-
this.end = this.end === undefined ? alleleEnd : Math.max(this.end, alleleEnd);
|
|
36701
|
-
}
|
|
36702
|
-
}
|
|
36703
|
-
|
|
36704
|
-
// Default to single base representation @ position for variant types not otherwise handled
|
|
36705
|
-
if (this.start === undefined) {
|
|
36706
|
-
this.start = this.pos - 1;
|
|
36707
|
-
this.end = this.pos;
|
|
36708
|
-
}
|
|
36709
|
-
}
|
|
36710
|
-
}
|
|
36711
|
-
}
|
|
36712
|
-
|
|
36713
|
-
|
|
36714
|
-
popupData(genomicLocation, genomeId) {
|
|
36715
|
-
|
|
36716
|
-
|
|
36717
|
-
const posString = `${numberFormatter$1(this.pos)}`;
|
|
36718
|
-
const locString = this.start === this.end ?
|
|
36719
|
-
`${numberFormatter$1(this.start)} | ${numberFormatter$1(this.start + 1)}` :
|
|
36720
|
-
`${numberFormatter$1(this.start + 1)}-${numberFormatter$1(this.end)}`;
|
|
36721
|
-
const fields = [
|
|
36722
|
-
{name: "Chr", value: this.chr},
|
|
36723
|
-
{name: "Pos", value: posString},
|
|
36724
|
-
{name: "Loc", value: locString},
|
|
36725
|
-
{name: "Names", value: this.names ? this.names : ""},
|
|
36726
|
-
{name: "Ref", value: this.referenceBases},
|
|
36727
|
-
{name: "Alt", value: this.alternateBases.replace("<", "<")},
|
|
36728
|
-
{name: "Qual", value: this.quality},
|
|
36729
|
-
{name: "Filter", value: this.filter}
|
|
36730
|
-
];
|
|
36731
|
-
|
|
36732
|
-
if ("SNP" === this.type) {
|
|
36733
|
-
let ref = this.referenceBases;
|
|
36734
|
-
if (ref.length === 1) {
|
|
36735
|
-
let altArray = this.alternateBases.split(",");
|
|
36736
|
-
for (let alt of altArray) {
|
|
36737
|
-
if (alt.length === 1) {
|
|
36738
|
-
let l = TrackBase.getCravatLink(this.chr, this.pos, ref, alt, genomeId);
|
|
36739
|
-
if (l) {
|
|
36740
|
-
fields.push('<hr/>');
|
|
36741
|
-
fields.push({html: l});
|
|
36742
|
-
}
|
|
36743
|
-
}
|
|
36744
|
-
}
|
|
36745
|
-
}
|
|
36746
|
-
}
|
|
36747
|
-
|
|
36748
|
-
if (this.hasOwnProperty("heterozygosity")) {
|
|
36749
|
-
fields.push({name: "Heterozygosity", value: this.heterozygosity});
|
|
36750
|
-
}
|
|
36751
|
-
|
|
36752
|
-
if (this.info) {
|
|
36753
|
-
fields.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
|
|
36754
|
-
for (let key of Object.keys(this.info)) {
|
|
36755
|
-
fields.push({name: key, value: arrayToString(decodeURIComponent(this.info[key]))});
|
|
36756
|
-
}
|
|
36757
|
-
}
|
|
36758
|
-
|
|
36759
|
-
return fields
|
|
36760
|
-
|
|
36761
|
-
};
|
|
36762
|
-
|
|
36763
|
-
isRefBlock() {
|
|
36764
|
-
return "NONVARIANT" === this.type
|
|
36765
|
-
}
|
|
36766
|
-
|
|
36767
|
-
}
|
|
36768
|
-
|
|
36769
|
-
function getInfoObject(infoStr) {
|
|
36770
|
-
var info = {};
|
|
37091
|
+
const variant = new Variant();
|
|
37092
|
+
variant.chr = tokens[0]; // TODO -- use genome aliases
|
|
37093
|
+
variant.pos = parseInt(tokens[1]);
|
|
37094
|
+
variant.names = tokens[2]; // id in VCF
|
|
37095
|
+
variant.referenceBases = tokens[3];
|
|
37096
|
+
variant.alternateBases = tokens[4];
|
|
37097
|
+
variant.quality = tokens[5];
|
|
37098
|
+
variant.filter = tokens[6];
|
|
37099
|
+
variant.info = {};
|
|
37100
|
+
const infoStr = tokens[7];
|
|
36771
37101
|
if (infoStr) {
|
|
36772
|
-
infoStr.split(';')
|
|
37102
|
+
for (let elem of infoStr.split(';')) {
|
|
36773
37103
|
var element = elem.split('=');
|
|
36774
|
-
info[element[0]] = element[1];
|
|
36775
|
-
});
|
|
36776
|
-
}
|
|
36777
|
-
return info
|
|
36778
|
-
}
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
function isKnownAlt(alt) {
|
|
36782
|
-
for (let i = 0; i < alt.length; i++) {
|
|
36783
|
-
if (!knownAltBases.has(alt.charCodeAt(i))) {
|
|
36784
|
-
return false
|
|
37104
|
+
variant.info[element[0]] = element[1];
|
|
36785
37105
|
}
|
|
36786
37106
|
}
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
function determineType(ref, altAlleles) {
|
|
36792
|
-
const refLength = ref.length;
|
|
36793
|
-
if (altAlleles === undefined) {
|
|
36794
|
-
return "UNKNOWN"
|
|
36795
|
-
} else if (altAlleles.trim().length === 0 ||
|
|
36796
|
-
altAlleles === "<NON_REF>" ||
|
|
36797
|
-
altAlleles === "<*>" ||
|
|
36798
|
-
altAlleles === ".") {
|
|
36799
|
-
return "NONVARIANT"
|
|
36800
|
-
} else {
|
|
36801
|
-
const alleles = altAlleles.split(",");
|
|
36802
|
-
const types = alleles.map(function (a) {
|
|
36803
|
-
if (refLength === 1 && a.length === 1) {
|
|
36804
|
-
return "SNP"
|
|
36805
|
-
} else {
|
|
36806
|
-
return "<NON_REF>" === a ? "NONVARIANT" : "OTHER"
|
|
36807
|
-
}
|
|
36808
|
-
});
|
|
36809
|
-
let type = types[0];
|
|
36810
|
-
for (let t of types) {
|
|
36811
|
-
if (t !== type) {
|
|
36812
|
-
return "MIXED"
|
|
36813
|
-
}
|
|
36814
|
-
}
|
|
36815
|
-
return type
|
|
36816
|
-
}
|
|
36817
|
-
}
|
|
36818
|
-
|
|
36819
|
-
function arrayToString(value, delim) {
|
|
36820
|
-
|
|
36821
|
-
if (delim === undefined) delim = ",";
|
|
36822
|
-
|
|
36823
|
-
if (!(Array.isArray(value))) {
|
|
36824
|
-
return value
|
|
36825
|
-
}
|
|
36826
|
-
return value.join(delim)
|
|
37107
|
+
variant.init();
|
|
37108
|
+
return variant;
|
|
36827
37109
|
}
|
|
36828
37110
|
|
|
36829
37111
|
|
|
@@ -36887,6 +37169,217 @@ function createGAVariant(json) {
|
|
|
36887
37169
|
|
|
36888
37170
|
}
|
|
36889
37171
|
|
|
37172
|
+
|
|
37173
|
+
class Variant {
|
|
37174
|
+
|
|
37175
|
+
init() {
|
|
37176
|
+
|
|
37177
|
+
const ref = this.referenceBases;
|
|
37178
|
+
const altBases = this.alternateBases;
|
|
37179
|
+
|
|
37180
|
+
if (this.info) {
|
|
37181
|
+
if (this.info["VT"]) {
|
|
37182
|
+
this.type = this.info["VT"];
|
|
37183
|
+
} else if (this.info["SVTYPE"]) {
|
|
37184
|
+
this.type = "SV";
|
|
37185
|
+
} else if (this.info["PERIOD"]) {
|
|
37186
|
+
this.type = "STR";
|
|
37187
|
+
}
|
|
37188
|
+
}
|
|
37189
|
+
if (this.type === undefined) {
|
|
37190
|
+
this.type = determineType(ref, altBases);
|
|
37191
|
+
}
|
|
37192
|
+
if (this.type === "NONVARIANT") {
|
|
37193
|
+
this.heterozygosity = 0;
|
|
37194
|
+
}
|
|
37195
|
+
|
|
37196
|
+
// Determine start/end coordinates -- these are the coordinates representing the actual variant,
|
|
37197
|
+
// not the leading or trailing reference
|
|
37198
|
+
if (this.info["END"]) {
|
|
37199
|
+
this.start = this.pos - 1;
|
|
37200
|
+
if (this.info["CHR2"] && this.info["CHR2"] !== this.chr) {
|
|
37201
|
+
this.end = this.start + 1;
|
|
37202
|
+
} else {
|
|
37203
|
+
this.end = Number.parseInt(this.info["END"]);
|
|
37204
|
+
}
|
|
37205
|
+
} else {
|
|
37206
|
+
if (this.type === "NONVARIANT") {
|
|
37207
|
+
this.start = this.pos - 1; // convert to 0-based coordinate convention
|
|
37208
|
+
this.end = this.start + ref.length;
|
|
37209
|
+
} else {
|
|
37210
|
+
|
|
37211
|
+
const altTokens = altBases.split(",").filter(token => token.length > 0);
|
|
37212
|
+
this.alleles = [];
|
|
37213
|
+
this.start = undefined;
|
|
37214
|
+
this.end = undefined;
|
|
37215
|
+
|
|
37216
|
+
for (let alt of altTokens) {
|
|
37217
|
+
|
|
37218
|
+
this.alleles.push(alt);
|
|
37219
|
+
|
|
37220
|
+
// We don't yet handle SV and other special alt representations
|
|
37221
|
+
if ("SV" !== this.type && isKnownAlt(alt)) {
|
|
37222
|
+
|
|
37223
|
+
let altLength = alt.length;
|
|
37224
|
+
let lengthOnRef = ref.length;
|
|
37225
|
+
const lmin = Math.min(altLength, lengthOnRef);
|
|
37226
|
+
|
|
37227
|
+
// Trim off matching bases. Try first match, then right -> left, then any remaining left -> right
|
|
37228
|
+
let s = 0;
|
|
37229
|
+
|
|
37230
|
+
while (s < lmin && (ref.charCodeAt(s) === alt.charCodeAt(s))) {
|
|
37231
|
+
s++;
|
|
37232
|
+
altLength--;
|
|
37233
|
+
lengthOnRef--;
|
|
37234
|
+
}
|
|
37235
|
+
|
|
37236
|
+
// right -> left from end
|
|
37237
|
+
while (altLength > 0 && lengthOnRef > 0) {
|
|
37238
|
+
const altIdx = s + altLength - 1;
|
|
37239
|
+
const refIdx = s + lengthOnRef - 1;
|
|
37240
|
+
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
37241
|
+
altLength--;
|
|
37242
|
+
lengthOnRef--;
|
|
37243
|
+
} else {
|
|
37244
|
+
break
|
|
37245
|
+
}
|
|
37246
|
+
}
|
|
37247
|
+
|
|
37248
|
+
// if any remaining, left -> right
|
|
37249
|
+
while (altLength > 0 && lengthOnRef > 0) {
|
|
37250
|
+
const altIdx = s;
|
|
37251
|
+
const refIdx = s;
|
|
37252
|
+
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
37253
|
+
s++;
|
|
37254
|
+
altLength--;
|
|
37255
|
+
lengthOnRef--;
|
|
37256
|
+
} else {
|
|
37257
|
+
break
|
|
37258
|
+
}
|
|
37259
|
+
}
|
|
37260
|
+
|
|
37261
|
+
const alleleStart = this.pos + s - 1; // -1 for zero based coordinates
|
|
37262
|
+
const alleleEnd = alleleStart + lengthOnRef;
|
|
37263
|
+
this.start = this.start === undefined ? alleleStart : Math.min(this.start, alleleStart);
|
|
37264
|
+
this.end = this.end === undefined ? alleleEnd : Math.max(this.end, alleleEnd);
|
|
37265
|
+
}
|
|
37266
|
+
}
|
|
37267
|
+
|
|
37268
|
+
// Default to single base representation @ position for variant types not otherwise handled
|
|
37269
|
+
if (this.start === undefined) {
|
|
37270
|
+
this.start = this.pos - 1;
|
|
37271
|
+
this.end = this.pos;
|
|
37272
|
+
}
|
|
37273
|
+
}
|
|
37274
|
+
}
|
|
37275
|
+
}
|
|
37276
|
+
|
|
37277
|
+
|
|
37278
|
+
popupData(genomicLocation, genomeId) {
|
|
37279
|
+
|
|
37280
|
+
|
|
37281
|
+
const posString = `${numberFormatter$1(this.pos)}`;
|
|
37282
|
+
const locString = this.start === this.end ?
|
|
37283
|
+
`${numberFormatter$1(this.start)} | ${numberFormatter$1(this.start + 1)}` :
|
|
37284
|
+
`${numberFormatter$1(this.start + 1)}-${numberFormatter$1(this.end)}`;
|
|
37285
|
+
const fields = [
|
|
37286
|
+
{name: "Chr", value: this.chr},
|
|
37287
|
+
{name: "Pos", value: posString},
|
|
37288
|
+
{name: "Loc", value: locString},
|
|
37289
|
+
{name: "Names", value: this.names ? this.names : ""},
|
|
37290
|
+
{name: "Ref", value: this.referenceBases},
|
|
37291
|
+
{name: "Alt", value: this.alternateBases.replace("<", "<")},
|
|
37292
|
+
{name: "Qual", value: this.quality},
|
|
37293
|
+
{name: "Filter", value: this.filter}
|
|
37294
|
+
];
|
|
37295
|
+
|
|
37296
|
+
if ("SNP" === this.type) {
|
|
37297
|
+
let ref = this.referenceBases;
|
|
37298
|
+
if (ref.length === 1) {
|
|
37299
|
+
let altArray = this.alternateBases.split(",");
|
|
37300
|
+
for (let alt of altArray) {
|
|
37301
|
+
if (alt.length === 1) {
|
|
37302
|
+
let l = TrackBase.getCravatLink(this.chr, this.pos, ref, alt, genomeId);
|
|
37303
|
+
if (l) {
|
|
37304
|
+
fields.push('<hr/>');
|
|
37305
|
+
fields.push({html: l});
|
|
37306
|
+
}
|
|
37307
|
+
}
|
|
37308
|
+
}
|
|
37309
|
+
}
|
|
37310
|
+
}
|
|
37311
|
+
|
|
37312
|
+
if (this.hasOwnProperty("heterozygosity")) {
|
|
37313
|
+
fields.push({name: "Heterozygosity", value: this.heterozygosity});
|
|
37314
|
+
}
|
|
37315
|
+
|
|
37316
|
+
if (this.info) {
|
|
37317
|
+
fields.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
|
|
37318
|
+
for (let key of Object.keys(this.info)) {
|
|
37319
|
+
fields.push({name: key, value: arrayToString(decodeURIComponent(this.info[key]))});
|
|
37320
|
+
}
|
|
37321
|
+
}
|
|
37322
|
+
|
|
37323
|
+
return fields
|
|
37324
|
+
|
|
37325
|
+
};
|
|
37326
|
+
|
|
37327
|
+
isRefBlock() {
|
|
37328
|
+
return "NONVARIANT" === this.type
|
|
37329
|
+
}
|
|
37330
|
+
|
|
37331
|
+
}
|
|
37332
|
+
|
|
37333
|
+
const knownAltBases = new Set(["A", "C", "T", "G"].map(c => c.charCodeAt(0)));
|
|
37334
|
+
|
|
37335
|
+
function isKnownAlt(alt) {
|
|
37336
|
+
for (let i = 0; i < alt.length; i++) {
|
|
37337
|
+
if (!knownAltBases.has(alt.charCodeAt(i))) {
|
|
37338
|
+
return false
|
|
37339
|
+
}
|
|
37340
|
+
}
|
|
37341
|
+
return true
|
|
37342
|
+
}
|
|
37343
|
+
|
|
37344
|
+
|
|
37345
|
+
function determineType(ref, altAlleles) {
|
|
37346
|
+
const refLength = ref.length;
|
|
37347
|
+
if (altAlleles === undefined) {
|
|
37348
|
+
return "UNKNOWN"
|
|
37349
|
+
} else if (altAlleles.trim().length === 0 ||
|
|
37350
|
+
altAlleles === "<NON_REF>" ||
|
|
37351
|
+
altAlleles === "<*>" ||
|
|
37352
|
+
altAlleles === ".") {
|
|
37353
|
+
return "NONVARIANT"
|
|
37354
|
+
} else {
|
|
37355
|
+
const alleles = altAlleles.split(",");
|
|
37356
|
+
const types = alleles.map(function (a) {
|
|
37357
|
+
if (refLength === 1 && a.length === 1) {
|
|
37358
|
+
return "SNP"
|
|
37359
|
+
} else {
|
|
37360
|
+
return "<NON_REF>" === a ? "NONVARIANT" : "OTHER"
|
|
37361
|
+
}
|
|
37362
|
+
});
|
|
37363
|
+
let type = types[0];
|
|
37364
|
+
for (let t of types) {
|
|
37365
|
+
if (t !== type) {
|
|
37366
|
+
return "MIXED"
|
|
37367
|
+
}
|
|
37368
|
+
}
|
|
37369
|
+
return type
|
|
37370
|
+
}
|
|
37371
|
+
}
|
|
37372
|
+
|
|
37373
|
+
function arrayToString(value, delim) {
|
|
37374
|
+
|
|
37375
|
+
if (delim === undefined) delim = ",";
|
|
37376
|
+
|
|
37377
|
+
if (!(Array.isArray(value))) {
|
|
37378
|
+
return value
|
|
37379
|
+
}
|
|
37380
|
+
return value.join(delim)
|
|
37381
|
+
}
|
|
37382
|
+
|
|
36890
37383
|
/*
|
|
36891
37384
|
* The MIT License (MIT)
|
|
36892
37385
|
*
|
|
@@ -37031,6 +37524,7 @@ class VcfParser {
|
|
|
37031
37524
|
if (tokens.length === nExpectedColumns) {
|
|
37032
37525
|
const variant = createVCFVariant(tokens);
|
|
37033
37526
|
variant.header = this.header; // Keep a pointer to the header to interpret fields for popup text
|
|
37527
|
+
//variant.line = line // Uncomment for debugging
|
|
37034
37528
|
allFeatures.push(variant);
|
|
37035
37529
|
|
|
37036
37530
|
if (tokens.length > 9) {
|
|
@@ -39153,6 +39647,7 @@ class HtsgetVariantReader extends HtsgetReader {
|
|
|
39153
39647
|
* THE SOFTWARE.
|
|
39154
39648
|
*/
|
|
39155
39649
|
|
|
39650
|
+
const DEFAULT_MAX_WG_COUNT = 10000;
|
|
39156
39651
|
|
|
39157
39652
|
/**
|
|
39158
39653
|
* feature source for "bed like" files (tab or whitespace delimited files with 1 feature per line: bed, gff, vcf, etc)
|
|
@@ -39167,8 +39662,9 @@ class TextFeatureSource {
|
|
|
39167
39662
|
this.config = config || {};
|
|
39168
39663
|
this.genome = genome;
|
|
39169
39664
|
this.sourceType = (config.sourceType === undefined ? "file" : config.sourceType);
|
|
39665
|
+
this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
|
|
39170
39666
|
|
|
39171
|
-
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "tdf"]);
|
|
39667
|
+
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "tdf"]);
|
|
39172
39668
|
|
|
39173
39669
|
if (config.features && Array.isArray(config.features)) {
|
|
39174
39670
|
// Explicit array of features
|
|
@@ -39384,10 +39880,22 @@ class TextFeatureSource {
|
|
|
39384
39880
|
// TODO -- filter by pixel size
|
|
39385
39881
|
getWGFeatures(allFeatures) {
|
|
39386
39882
|
|
|
39883
|
+
const makeWGFeature = (f) => {
|
|
39884
|
+
const wg = Object.assign({}, f);
|
|
39885
|
+
wg.chr = "all";
|
|
39886
|
+
wg.start = genome.getGenomeCoordinate(f.chr, f.start);
|
|
39887
|
+
wg.end = genome.getGenomeCoordinate(f.chr, f.end);
|
|
39888
|
+
wg._f = f;
|
|
39889
|
+
// Don't draw exons in whole genome view
|
|
39890
|
+
if (wg["exons"]) delete wg["exons"];
|
|
39891
|
+
return wg
|
|
39892
|
+
};
|
|
39893
|
+
|
|
39387
39894
|
const genome = this.genome;
|
|
39388
39895
|
const wgChromosomeNames = new Set(genome.wgChromosomeNames);
|
|
39389
39896
|
const wgFeatures = [];
|
|
39390
|
-
|
|
39897
|
+
let count = 0;
|
|
39898
|
+
const max = this.maxWGCount;
|
|
39391
39899
|
for (let c of genome.wgChromosomeNames) {
|
|
39392
39900
|
|
|
39393
39901
|
const features = allFeatures[c];
|
|
@@ -39396,19 +39904,18 @@ class TextFeatureSource {
|
|
|
39396
39904
|
for (let f of features) {
|
|
39397
39905
|
let queryChr = genome.getChromosomeName(f.chr);
|
|
39398
39906
|
if (wgChromosomeNames.has(queryChr)) {
|
|
39399
|
-
|
|
39400
|
-
|
|
39401
|
-
|
|
39402
|
-
|
|
39403
|
-
|
|
39404
|
-
|
|
39405
|
-
|
|
39406
|
-
|
|
39407
|
-
|
|
39408
|
-
|
|
39409
|
-
|
|
39410
|
-
wgFeatures.push(wg);
|
|
39907
|
+
if (wgFeatures.length < max) {
|
|
39908
|
+
wgFeatures.push(makeWGFeature(f));
|
|
39909
|
+
} else {
|
|
39910
|
+
//Reservoir sampling
|
|
39911
|
+
const samplingProb = max / (count + 1);
|
|
39912
|
+
if (Math.random() < samplingProb) {
|
|
39913
|
+
const idx = Math.floor(Math.random() * (max - 1));
|
|
39914
|
+
wgFeatures[idx] = makeWGFeature(f);
|
|
39915
|
+
}
|
|
39916
|
+
}
|
|
39411
39917
|
}
|
|
39918
|
+
count++;
|
|
39412
39919
|
}
|
|
39413
39920
|
}
|
|
39414
39921
|
}
|
|
@@ -39579,9 +40086,9 @@ class BufferedReader {
|
|
|
39579
40086
|
|
|
39580
40087
|
//table chromatinInteract
|
|
39581
40088
|
|
|
39582
|
-
function getDecoder(definedFieldCount, fieldCount, autoSql) {
|
|
40089
|
+
function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
39583
40090
|
|
|
39584
|
-
if (autoSql && 'chromatinInteract' === autoSql.table) {
|
|
40091
|
+
if (autoSql && 'chromatinInteract' === autoSql.table || "biginteract" === format) {
|
|
39585
40092
|
return decodeInteract
|
|
39586
40093
|
} else {
|
|
39587
40094
|
const standardFieldCount = definedFieldCount - 3;
|
|
@@ -39728,6 +40235,7 @@ class BWReader {
|
|
|
39728
40235
|
|
|
39729
40236
|
constructor(config, genome) {
|
|
39730
40237
|
this.path = config.url;
|
|
40238
|
+
this.format = config.format || "bigwig";
|
|
39731
40239
|
this.genome = genome;
|
|
39732
40240
|
this.rpTreeCache = {};
|
|
39733
40241
|
this.config = config;
|
|
@@ -40328,7 +40836,7 @@ function decodeWigData(data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, chr
|
|
|
40328
40836
|
function getBedDataDecoder() {
|
|
40329
40837
|
|
|
40330
40838
|
const minSize = 3 * 4 + 1; // Minimum # of bytes required for a bed record
|
|
40331
|
-
const decoder = getDecoder(this.header.definedFieldCount, this.header.fieldCount, this.autoSql);
|
|
40839
|
+
const decoder = getDecoder(this.header.definedFieldCount, this.header.fieldCount, this.autoSql, this.format);
|
|
40332
40840
|
return function (data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, chrDict) {
|
|
40333
40841
|
const binaryParser = new BinaryParser(data);
|
|
40334
40842
|
while (binaryParser.remLength() >= minSize) {
|
|
@@ -41196,7 +41704,7 @@ function zoomLevelForScale(chr, bpPerPixel, genome) {
|
|
|
41196
41704
|
function FeatureSource(config, genome) {
|
|
41197
41705
|
|
|
41198
41706
|
const format = config.format ? config.format.toLowerCase() : undefined;
|
|
41199
|
-
if ('bigwig' === format || 'bigbed' === format || 'bb' === format) {
|
|
41707
|
+
if ('bigwig' === format || 'bigbed' === format || 'bb' === format || "biginteract" === format) {
|
|
41200
41708
|
return new BWSource(config, genome)
|
|
41201
41709
|
} else if ("tdf" === format) {
|
|
41202
41710
|
return new TDFSource(config, genome)
|
|
@@ -41337,7 +41845,7 @@ function renderFeature(feature, bpStart, xScale, pixelHeight, ctx, options) {
|
|
|
41337
41845
|
// single-exon transcript
|
|
41338
41846
|
const xLeft = Math.max(0, coord.px);
|
|
41339
41847
|
const xRight = Math.min(pixelWidth, coord.px1);
|
|
41340
|
-
const width =
|
|
41848
|
+
const width = xRight - xLeft;
|
|
41341
41849
|
ctx.fillRect(xLeft, py, width, h);
|
|
41342
41850
|
|
|
41343
41851
|
// Arrows
|
|
@@ -42062,7 +42570,7 @@ class FeatureTrack extends TrackBase {
|
|
|
42062
42570
|
desc += "</html>";
|
|
42063
42571
|
return desc
|
|
42064
42572
|
} else {
|
|
42065
|
-
return
|
|
42573
|
+
return super.description();
|
|
42066
42574
|
}
|
|
42067
42575
|
|
|
42068
42576
|
};
|
|
@@ -42144,8 +42652,12 @@ class WigTrack extends TrackBase {
|
|
|
42144
42652
|
|
|
42145
42653
|
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
42146
42654
|
if ("bigwig" === format) {
|
|
42655
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
42656
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
42147
42657
|
this.featureSource = new BWSource(config, this.browser.genome);
|
|
42148
42658
|
} else if ("tdf" === format) {
|
|
42659
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
42660
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
42149
42661
|
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
42150
42662
|
} else {
|
|
42151
42663
|
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
@@ -42194,7 +42706,20 @@ class WigTrack extends TrackBase {
|
|
|
42194
42706
|
}
|
|
42195
42707
|
|
|
42196
42708
|
menuItemList() {
|
|
42197
|
-
|
|
42709
|
+
let items = [];
|
|
42710
|
+
if (this.flipAxis !== undefined) {
|
|
42711
|
+
items.push({
|
|
42712
|
+
label:"Flip y-axis",
|
|
42713
|
+
click: () => {
|
|
42714
|
+
this.flipAxis = !this.flipAxis;
|
|
42715
|
+
this.trackView.repaintViews();
|
|
42716
|
+
}
|
|
42717
|
+
});
|
|
42718
|
+
}
|
|
42719
|
+
|
|
42720
|
+
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
42721
|
+
|
|
42722
|
+
return items
|
|
42198
42723
|
}
|
|
42199
42724
|
|
|
42200
42725
|
async getHeader() {
|
|
@@ -42205,6 +42730,27 @@ class WigTrack extends TrackBase {
|
|
|
42205
42730
|
return this.header
|
|
42206
42731
|
}
|
|
42207
42732
|
|
|
42733
|
+
// TODO: refactor to igvUtils.js
|
|
42734
|
+
getScaleFactor(min, max, height, logScale) {
|
|
42735
|
+
const scale = logScale ? height / (Math.log10(max + 1) - (min <= 0 ? 0 : Math.log10(min + 1))) : height / (max - min);
|
|
42736
|
+
return scale
|
|
42737
|
+
}
|
|
42738
|
+
|
|
42739
|
+
computeYPixelValue(yValue, yScaleFactor) {
|
|
42740
|
+
return (this.flipAxis ? (yValue - this.dataRange.min) : (this.dataRange.max - yValue)) * yScaleFactor
|
|
42741
|
+
}
|
|
42742
|
+
|
|
42743
|
+
computeYPixelValueInLogScale(yValue, yScaleFactor) {
|
|
42744
|
+
let maxValue = this.dataRange.max;
|
|
42745
|
+
let minValue = this.dataRange.min;
|
|
42746
|
+
if (maxValue <= 0) return 0 // TODO:
|
|
42747
|
+
if (minValue <= -1) minValue = 0;
|
|
42748
|
+
minValue = (minValue <= 0) ? 0 : Math.log10(minValue + 1);
|
|
42749
|
+
maxValue = Math.log10(maxValue + 1);
|
|
42750
|
+
yValue = Math.log10(yValue + 1);
|
|
42751
|
+
return ((this.flipAxis ? (yValue - minValue) : (maxValue - yValue)) * yScaleFactor)
|
|
42752
|
+
}
|
|
42753
|
+
|
|
42208
42754
|
draw(options) {
|
|
42209
42755
|
|
|
42210
42756
|
const features = options.features;
|
|
@@ -42212,7 +42758,7 @@ class WigTrack extends TrackBase {
|
|
|
42212
42758
|
const bpPerPixel = options.bpPerPixel;
|
|
42213
42759
|
const bpStart = options.bpStart;
|
|
42214
42760
|
const pixelWidth = options.pixelWidth;
|
|
42215
|
-
|
|
42761
|
+
options.pixelHeight;
|
|
42216
42762
|
const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
|
|
42217
42763
|
let lastPixelEnd = -1;
|
|
42218
42764
|
let lastValue = -1;
|
|
@@ -42224,9 +42770,10 @@ class WigTrack extends TrackBase {
|
|
|
42224
42770
|
baselineColor = IGVColor.addAlpha(posColor, 0.1);
|
|
42225
42771
|
}
|
|
42226
42772
|
|
|
42227
|
-
const
|
|
42228
|
-
|
|
42229
|
-
|
|
42773
|
+
const scaleFactor = this.getScaleFactor(this.dataRange.min, this.dataRange.max, options.pixelHeight, this.logScale);
|
|
42774
|
+
const yScale = (yValue) => this.logScale
|
|
42775
|
+
? this.computeYPixelValueInLogScale(yValue, scaleFactor)
|
|
42776
|
+
: this.computeYPixelValue(yValue, scaleFactor);
|
|
42230
42777
|
|
|
42231
42778
|
if (features && features.length > 0) {
|
|
42232
42779
|
|
|
@@ -42236,7 +42783,7 @@ class WigTrack extends TrackBase {
|
|
|
42236
42783
|
// nothing to paint.
|
|
42237
42784
|
if (this.dataRange.max > this.dataRange.min) {
|
|
42238
42785
|
|
|
42239
|
-
const y0 =
|
|
42786
|
+
const y0 = yScale(0);
|
|
42240
42787
|
for (let f of features) {
|
|
42241
42788
|
|
|
42242
42789
|
if (f.end < bpStart) continue
|
|
@@ -42260,9 +42807,6 @@ class WigTrack extends TrackBase {
|
|
|
42260
42807
|
|
|
42261
42808
|
} else {
|
|
42262
42809
|
let height = y - y0;
|
|
42263
|
-
if ((Math.abs(height)) < 1) {
|
|
42264
|
-
height = height < 0 ? -1 : 1;
|
|
42265
|
-
}
|
|
42266
42810
|
const pixelEnd = x + width;
|
|
42267
42811
|
if (pixelEnd > lastPixelEnd || (f.value >= 0 && f.value > lastValue) || (f.value < 0 && f.value < lastNegValue)) {
|
|
42268
42812
|
IGVGraphics.fillRect(ctx, x, y0, width, height, {fillStyle: color});
|
|
@@ -42359,6 +42903,21 @@ class WigTrack extends TrackBase {
|
|
|
42359
42903
|
dispose() {
|
|
42360
42904
|
this.trackView = undefined;
|
|
42361
42905
|
}
|
|
42906
|
+
|
|
42907
|
+
/**
|
|
42908
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
42909
|
+
*
|
|
42910
|
+
* @returns {*|{}}
|
|
42911
|
+
*/
|
|
42912
|
+
getState() {
|
|
42913
|
+
|
|
42914
|
+
const config = super.getState();
|
|
42915
|
+
|
|
42916
|
+
if (this.flipAxis !== undefined) config.flipAxis = this.flipAxis;
|
|
42917
|
+
if (this.logScale !== undefined) config.logScale = this.logScale;
|
|
42918
|
+
|
|
42919
|
+
return config
|
|
42920
|
+
}
|
|
42362
42921
|
}
|
|
42363
42922
|
|
|
42364
42923
|
/**
|
|
@@ -42523,7 +43082,11 @@ class SegTrack extends TrackBase {
|
|
|
42523
43082
|
|
|
42524
43083
|
// this.featureSource = config.sourceType === "bigquery" ?
|
|
42525
43084
|
// new igv.BigQueryFeatureSource(this.config) :
|
|
42526
|
-
|
|
43085
|
+
|
|
43086
|
+
// Disable whole genome downsampling unless explicitly.
|
|
43087
|
+
const configCopy = Object.assign({}, this.config);
|
|
43088
|
+
configCopy.maxWGCount = configCopy.maxWGCount || Number.MAX_SAFE_INTEGER;
|
|
43089
|
+
this.featureSource = FeatureSource(configCopy, this.browser.genome);
|
|
42527
43090
|
|
|
42528
43091
|
this.initialSort = config.sort;
|
|
42529
43092
|
}
|
|
@@ -43173,6 +43736,19 @@ function autoscale(chr, featureArrays) {
|
|
|
43173
43736
|
* THE SOFTWARE.
|
|
43174
43737
|
*/
|
|
43175
43738
|
|
|
43739
|
+
function getArcType(config) {
|
|
43740
|
+
if (!config.arcType) {
|
|
43741
|
+
return "nested"
|
|
43742
|
+
}
|
|
43743
|
+
switch (config.arcType) {
|
|
43744
|
+
case "chiapet":
|
|
43745
|
+
return "inView"
|
|
43746
|
+
case "chiapetoutbound":
|
|
43747
|
+
return "partialInView"
|
|
43748
|
+
default:
|
|
43749
|
+
return config.arcType
|
|
43750
|
+
}
|
|
43751
|
+
}
|
|
43176
43752
|
|
|
43177
43753
|
class InteractionTrack extends TrackBase {
|
|
43178
43754
|
|
|
@@ -43187,13 +43763,14 @@ class InteractionTrack extends TrackBase {
|
|
|
43187
43763
|
this.sinTheta = Math.sin(this.theta);
|
|
43188
43764
|
this.cosTheta = Math.cos(this.theta);
|
|
43189
43765
|
this.height = config.height || 250;
|
|
43190
|
-
this.arcType = config
|
|
43766
|
+
this.arcType = getArcType(config); // nested | proportional | inView | partialInView
|
|
43191
43767
|
this.arcOrientation = (config.arcOrientation === undefined ? true : config.arcOrientation); // true for up, false for down
|
|
43192
43768
|
this.showBlocks = config.showBlocks === undefined ? true : config.showBlocks;
|
|
43193
43769
|
this.blockHeight = config.blockHeight || 3;
|
|
43194
43770
|
this.thickness = config.thickness || 1;
|
|
43195
43771
|
this.color = config.color || "rgb(180,25,137)";
|
|
43196
|
-
this.alpha = config.alpha || 0.15
|
|
43772
|
+
this.alpha = config.alpha || 0.02; // was: 0.15
|
|
43773
|
+
this.painter = {flipAxis: !this.arcOrientation, dataRange: this.dataRange, paintAxis: paintAxis};
|
|
43197
43774
|
|
|
43198
43775
|
if (config.valueColumn) {
|
|
43199
43776
|
this.valueColumn = config.valueColumn;
|
|
@@ -43258,6 +43835,8 @@ class InteractionTrack extends TrackBase {
|
|
|
43258
43835
|
|
|
43259
43836
|
if (this.arcType === "proportional") {
|
|
43260
43837
|
this.drawProportional(options);
|
|
43838
|
+
} else if (this.arcType === "inView" || this.arcType === "partialInView") {
|
|
43839
|
+
this.drawProportional(options);
|
|
43261
43840
|
} else {
|
|
43262
43841
|
this.drawNested(options);
|
|
43263
43842
|
}
|
|
@@ -43289,6 +43868,9 @@ class InteractionTrack extends TrackBase {
|
|
|
43289
43868
|
|
|
43290
43869
|
for (let feature of featureList) {
|
|
43291
43870
|
|
|
43871
|
+
// Reset transient property drawState. An undefined value => feature has not been drawn.
|
|
43872
|
+
feature.drawState = undefined;
|
|
43873
|
+
|
|
43292
43874
|
let color = feature.color || this.color;
|
|
43293
43875
|
if (color && this.config.useScore) {
|
|
43294
43876
|
color = getAlphaColor(color, scoreShade(feature.score));
|
|
@@ -43358,7 +43940,10 @@ class InteractionTrack extends TrackBase {
|
|
|
43358
43940
|
}
|
|
43359
43941
|
const otherChr = feature.chr === feature.chr1 ? feature.chr2 : feature.chr1;
|
|
43360
43942
|
ctx.strokeStyle = color;
|
|
43361
|
-
|
|
43943
|
+
// get a sense of trans "spread"
|
|
43944
|
+
ctx.fillStyle = getAlphaColor(getChrColor(otherChr), 0.5);
|
|
43945
|
+
// ctx.fillStyle = color
|
|
43946
|
+
|
|
43362
43947
|
if (direction) {
|
|
43363
43948
|
// UP
|
|
43364
43949
|
ctx.fillRect(pixelStart, this.height / 2, w, this.height / 2);
|
|
@@ -43392,6 +43977,11 @@ class InteractionTrack extends TrackBase {
|
|
|
43392
43977
|
}
|
|
43393
43978
|
}
|
|
43394
43979
|
|
|
43980
|
+
getScaleFactor(min, max, height, logScale) {
|
|
43981
|
+
const scale = logScale ? height / (Math.log10(max + 1) - (min <= 0 ? 0 : Math.log10(min + 1))) : height / (max - min);
|
|
43982
|
+
return scale
|
|
43983
|
+
}
|
|
43984
|
+
|
|
43395
43985
|
drawProportional(options) {
|
|
43396
43986
|
|
|
43397
43987
|
const ctx = options.context;
|
|
@@ -43400,12 +43990,9 @@ class InteractionTrack extends TrackBase {
|
|
|
43400
43990
|
const bpPerPixel = options.bpPerPixel;
|
|
43401
43991
|
const bpStart = options.bpStart;
|
|
43402
43992
|
const xScale = bpPerPixel;
|
|
43993
|
+
const refStart = options.referenceFrame.start;
|
|
43994
|
+
const refEnd = options.referenceFrame.end;
|
|
43403
43995
|
|
|
43404
|
-
// SVG output for proportional arcs are currently not supported because "ellipse" is not implemented
|
|
43405
|
-
// if(typeof ctx.ellipse !== 'function') {
|
|
43406
|
-
// Alert.presentAlert("SVG output of proportional arcs is currently not supported.")
|
|
43407
|
-
// return;
|
|
43408
|
-
// }
|
|
43409
43996
|
|
|
43410
43997
|
IGVGraphics.fillRect(ctx, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
43411
43998
|
|
|
@@ -43413,37 +44000,65 @@ class InteractionTrack extends TrackBase {
|
|
|
43413
44000
|
|
|
43414
44001
|
if (featureList && featureList.length > 0) {
|
|
43415
44002
|
|
|
43416
|
-
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
44003
|
+
// we use the min as a filter but not moving the axis
|
|
44004
|
+
const effectiveMin = 0;
|
|
44005
|
+
const yScale = this.getScaleFactor(effectiveMin, this.dataRange.max, options.pixelHeight - 1, this.logScale);
|
|
43420
44006
|
const y = this.arcOrientation ? options.pixelHeight : 0;
|
|
43421
44007
|
|
|
43422
44008
|
for (let feature of featureList) {
|
|
43423
44009
|
|
|
44010
|
+
// Reset transient property drawState. An undefined value => feature has not been drawn.
|
|
44011
|
+
feature.drawState = undefined;
|
|
44012
|
+
|
|
43424
44013
|
const value = this.valueColumn ? feature[this.valueColumn] : feature.score;
|
|
43425
44014
|
if (value === undefined || Number.isNaN(value)) continue
|
|
43426
44015
|
|
|
43427
|
-
const radiusY = this.logScale ?
|
|
43428
|
-
Math.log10(value + 1) * yScale :
|
|
43429
|
-
value * yScale;
|
|
44016
|
+
const radiusY = Math.round((this.logScale ? Math.log10(value + 1) : value) * yScale);
|
|
43430
44017
|
|
|
43431
44018
|
if (feature.chr1 === feature.chr2 || feature.chr === 'all') {
|
|
43432
44019
|
|
|
43433
44020
|
const {m1, m2} = getMidpoints(feature, this.browser.genome);
|
|
43434
44021
|
|
|
43435
|
-
let pixelStart = (m1 - bpStart) / xScale;
|
|
43436
|
-
let pixelEnd = (m2 - bpStart) / xScale;
|
|
44022
|
+
let pixelStart = Math.round((m1 - bpStart) / xScale);
|
|
44023
|
+
let pixelEnd = Math.round((m2 - bpStart) / xScale);
|
|
43437
44024
|
let w = (pixelEnd - pixelStart);
|
|
43438
44025
|
if (w < 3) {
|
|
43439
44026
|
w = 3;
|
|
43440
44027
|
pixelStart--;
|
|
43441
44028
|
}
|
|
43442
44029
|
|
|
43443
|
-
|
|
44030
|
+
// Various filters
|
|
44031
|
+
if (value < this.dataRange.min || value > this.dataRange.max) continue
|
|
44032
|
+
if ("proportional" !== this.arcType) {
|
|
44033
|
+
const showOutbound = (this.arcType === "partialInView");
|
|
44034
|
+
const within = (m1 >= refStart && m2 <= refEnd);
|
|
44035
|
+
let outBound = false;
|
|
44036
|
+
let inBound = false;
|
|
44037
|
+
if (!within && showOutbound) {
|
|
44038
|
+
outBound = (refStart <= m1 && m1 <= refEnd);
|
|
44039
|
+
if (!outBound) inBound = (refStart <= m2 && m2 <= refEnd);
|
|
44040
|
+
}
|
|
44041
|
+
if (!(within || outBound || inBound)) continue
|
|
44042
|
+
}
|
|
44043
|
+
|
|
43444
44044
|
|
|
43445
44045
|
const radiusX = w / 2;
|
|
43446
44046
|
const xc = pixelStart + w / 2;
|
|
44047
|
+
feature.drawState = {xc, yc: y, radiusX, radiusY};
|
|
44048
|
+
|
|
44049
|
+
// const arcKey = ((pixelStart << 16) | pixelEnd)
|
|
44050
|
+
// let arc = arcCaches.get(arcKey)
|
|
44051
|
+
// if (arc !== undefined) {
|
|
44052
|
+
// if (arc.has(radiusY)) {
|
|
44053
|
+
// continue
|
|
44054
|
+
// }
|
|
44055
|
+
// arc.add(radiusY)
|
|
44056
|
+
// } else {
|
|
44057
|
+
// let arcHeights = new Set()
|
|
44058
|
+
// arcHeights.add(radiusY)
|
|
44059
|
+
// arcCaches.set(arcKey, arcHeights)
|
|
44060
|
+
// }
|
|
44061
|
+
|
|
43447
44062
|
const counterClockwise = this.arcOrientation ? true : false;
|
|
43448
44063
|
const color = feature.color || this.color;
|
|
43449
44064
|
ctx.strokeStyle = color;
|
|
@@ -43457,6 +44072,15 @@ class InteractionTrack extends TrackBase {
|
|
|
43457
44072
|
ctx.stroke();
|
|
43458
44073
|
}
|
|
43459
44074
|
|
|
44075
|
+
if (this.alpha) {
|
|
44076
|
+
ctx.fillStyle = getAlphaColor(color, this.alpha);
|
|
44077
|
+
if (true === ctx.isSVG) {
|
|
44078
|
+
ctx.fillEllipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise);
|
|
44079
|
+
} else {
|
|
44080
|
+
ctx.fill();
|
|
44081
|
+
}
|
|
44082
|
+
}
|
|
44083
|
+
|
|
43460
44084
|
if (this.showBlocks && feature.chr !== 'all') {
|
|
43461
44085
|
ctx.fillStyle = color;
|
|
43462
44086
|
const s1 = (feature.start1 - bpStart) / xScale;
|
|
@@ -43468,21 +44092,11 @@ class InteractionTrack extends TrackBase {
|
|
|
43468
44092
|
ctx.fillRect(s2, y, e2 - s2, hb);
|
|
43469
44093
|
}
|
|
43470
44094
|
|
|
43471
|
-
if (this.alpha) {
|
|
43472
|
-
ctx.fillStyle = getAlphaColor(color, this.alpha);
|
|
43473
|
-
if (true === ctx.isSVG) {
|
|
43474
|
-
ctx.fillEllipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise);
|
|
43475
|
-
} else {
|
|
43476
|
-
ctx.fill();
|
|
43477
|
-
}
|
|
43478
|
-
|
|
43479
|
-
}
|
|
43480
|
-
|
|
43481
|
-
feature.drawState = {xc, yc: y, radiusX, radiusY};
|
|
43482
44095
|
} else {
|
|
44096
|
+
// Inter chromosome
|
|
43483
44097
|
let pixelStart = Math.round((feature.start - bpStart) / xScale);
|
|
43484
44098
|
let pixelEnd = Math.round((feature.end - bpStart) / xScale);
|
|
43485
|
-
if (pixelEnd < 0 || pixelStart > pixelWidth || value < this.dataRange.min) continue
|
|
44099
|
+
if (pixelEnd < 0 || pixelStart > pixelWidth || value < this.dataRange.min || value > this.dataRange.max) continue
|
|
43486
44100
|
|
|
43487
44101
|
const h = Math.min(radiusY, this.height - 13); // Leave room for text
|
|
43488
44102
|
let w = (pixelEnd - pixelStart);
|
|
@@ -43493,6 +44107,8 @@ class InteractionTrack extends TrackBase {
|
|
|
43493
44107
|
const otherChr = feature.chr === feature.chr1 ? feature.chr2 : feature.chr1;
|
|
43494
44108
|
ctx.font = "8px sans-serif";
|
|
43495
44109
|
ctx.textAlign = "center";
|
|
44110
|
+
// get a sense of trans "spread"
|
|
44111
|
+
ctx.fillStyle = getAlphaColor(getChrColor(otherChr), 0.5);
|
|
43496
44112
|
if (this.arcOrientation) {
|
|
43497
44113
|
// UP
|
|
43498
44114
|
const y = this.height - h;
|
|
@@ -43509,6 +44125,26 @@ class InteractionTrack extends TrackBase {
|
|
|
43509
44125
|
}
|
|
43510
44126
|
}
|
|
43511
44127
|
|
|
44128
|
+
clearAxis(ctx, pixelWidth, pixelHeight) {
|
|
44129
|
+
IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
44130
|
+
}
|
|
44131
|
+
|
|
44132
|
+
paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
44133
|
+
// dataRane is interpreted differently for interactino tracks -- all arcs are drawn from "zero", irrespective of dataRange.min
|
|
44134
|
+
const axisRange = {min: 0, max: this.dataRange.max};
|
|
44135
|
+
if (this.arcType === "proportional") {
|
|
44136
|
+
this.painter.flipAxis = !this.arcOrientation;
|
|
44137
|
+
this.painter.dataRange = axisRange;
|
|
44138
|
+
this.painter.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
44139
|
+
} else if (this.arcType === "inView" || this.arcType === "partialInView") {
|
|
44140
|
+
this.painter.flipAxis = !this.arcOrientation;
|
|
44141
|
+
this.painter.dataRange = axisRange;
|
|
44142
|
+
this.painter.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
44143
|
+
} else {
|
|
44144
|
+
this.clearAxis(ctx, pixelWidth, pixelHeight);
|
|
44145
|
+
}
|
|
44146
|
+
}
|
|
44147
|
+
|
|
43512
44148
|
menuItemList() {
|
|
43513
44149
|
|
|
43514
44150
|
let items = [
|
|
@@ -43525,10 +44161,13 @@ class InteractionTrack extends TrackBase {
|
|
|
43525
44161
|
if (this.hasValue) {
|
|
43526
44162
|
const lut =
|
|
43527
44163
|
{
|
|
43528
|
-
"nested": "Nested
|
|
43529
|
-
"proportional": "Proportional
|
|
44164
|
+
"nested": "Nested",
|
|
44165
|
+
"proportional": "Proportional - All",
|
|
44166
|
+
"inView": "Proportional - Both Ends in View",
|
|
44167
|
+
"partialInView": "Proportional - One End in View"
|
|
43530
44168
|
};
|
|
43531
|
-
|
|
44169
|
+
items.push("<b>Arc Type</b>");
|
|
44170
|
+
for (let arcType of ["nested", "proportional", "inView", "partialInView"]) {
|
|
43532
44171
|
items.push(
|
|
43533
44172
|
{
|
|
43534
44173
|
object: $$1(createCheckbox$1(lut[arcType], arcType === this.arcType)),
|
|
@@ -43539,45 +44178,37 @@ class InteractionTrack extends TrackBase {
|
|
|
43539
44178
|
});
|
|
43540
44179
|
}
|
|
43541
44180
|
}
|
|
44181
|
+
items.push("<hr/>");
|
|
43542
44182
|
|
|
43543
44183
|
items.push({
|
|
43544
|
-
|
|
44184
|
+
name: "Toggle arc direction",
|
|
43545
44185
|
click: () => {
|
|
43546
|
-
this.
|
|
44186
|
+
this.arcOrientation = !this.arcOrientation;
|
|
43547
44187
|
this.trackView.repaintViews();
|
|
43548
44188
|
}
|
|
43549
44189
|
});
|
|
43550
44190
|
items.push({
|
|
43551
|
-
name: "
|
|
44191
|
+
name: this.showBlocks ? "Hide Blocks" : "Show Blocks",
|
|
43552
44192
|
click: () => {
|
|
43553
|
-
this.
|
|
44193
|
+
this.showBlocks = !this.showBlocks;
|
|
43554
44194
|
this.trackView.repaintViews();
|
|
43555
44195
|
}
|
|
43556
44196
|
});
|
|
43557
44197
|
|
|
43558
|
-
|
|
43559
|
-
|
|
44198
|
+
|
|
44199
|
+
if (this.arcType === "proportional" || this.arcType === "inView" || this.arcType === "partialInView") {
|
|
44200
|
+
// MenuUtils.numericDataMenuItems(this.trackView).forEach(item => items.push(item))
|
|
43560
44201
|
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
43561
44202
|
}
|
|
43562
44203
|
|
|
43563
44204
|
if (this.browser.circularView && true === this.browser.circularViewVisible) {
|
|
44205
|
+
items.push('<hr/>');
|
|
43564
44206
|
items.push({
|
|
43565
44207
|
label: 'Add interactions to circular view',
|
|
43566
44208
|
click: () => {
|
|
43567
|
-
|
|
43568
|
-
const inView = [];
|
|
43569
44209
|
for (let viewport of this.trackView.viewports) {
|
|
43570
|
-
|
|
43571
|
-
for (let f of viewport.getCachedFeatures()) {
|
|
43572
|
-
if (f.end >= refFrame.start && f.start <= refFrame.end) {
|
|
43573
|
-
inView.push(f);
|
|
43574
|
-
}
|
|
43575
|
-
}
|
|
44210
|
+
this.addChordsForViewport(viewport.referenceFrame);
|
|
43576
44211
|
}
|
|
43577
|
-
|
|
43578
|
-
const chords = makeBedPEChords(inView);
|
|
43579
|
-
const color = IGVColor.addAlpha(this.color, 0.5);
|
|
43580
|
-
this.browser.circularView.addChords(chords, {track: this.name, color: color});
|
|
43581
44212
|
}
|
|
43582
44213
|
});
|
|
43583
44214
|
}
|
|
@@ -43596,22 +44227,43 @@ class InteractionTrack extends TrackBase {
|
|
|
43596
44227
|
label: 'Add interactions to circular view',
|
|
43597
44228
|
click: () => {
|
|
43598
44229
|
const refFrame = viewport.referenceFrame;
|
|
43599
|
-
|
|
43600
|
-
|
|
43601
|
-
this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
43602
|
-
this.browser.circularViewVisible = true;
|
|
43603
|
-
const chords = makeBedPEChords(inView);
|
|
43604
|
-
const color = IGVColor.addAlpha(this.color, 0.5);
|
|
43605
|
-
this.browser.circularView.addChords(chords, {track: this.name, color: color});
|
|
44230
|
+
// first pass: to get all the relevant features
|
|
44231
|
+
this.addChordsForViewport(refFrame);
|
|
43606
44232
|
}
|
|
43607
44233
|
});
|
|
43608
44234
|
|
|
43609
44235
|
list.push('<hr/>');
|
|
43610
44236
|
return list
|
|
43611
44237
|
}
|
|
43612
|
-
|
|
43613
44238
|
}
|
|
43614
44239
|
|
|
44240
|
+
/**
|
|
44241
|
+
* Add chords to the circular view for the given viewport, represented by its reference frame
|
|
44242
|
+
* @param refFrame
|
|
44243
|
+
*/
|
|
44244
|
+
addChordsForViewport(refFrame) {
|
|
44245
|
+
const cachedFeatures = "all" === refFrame.chr ?
|
|
44246
|
+
this.featureSource.getAllFeatures() :
|
|
44247
|
+
this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
44248
|
+
|
|
44249
|
+
// inView features are simply features that have been drawn, i.e. have a drawState
|
|
44250
|
+
const inView = cachedFeatures.filter(f => f.drawState);
|
|
44251
|
+
if(inView.length === 0) erturn;
|
|
44252
|
+
|
|
44253
|
+
this.browser.circularViewVisible = true;
|
|
44254
|
+
const chords = makeBedPEChords(inView);
|
|
44255
|
+
|
|
44256
|
+
// for filtered set, distinguishing the chromosomes is more critical than tracks
|
|
44257
|
+
const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.5);
|
|
44258
|
+
const trackColor = IGVColor.addAlpha(this.color, 0.5);
|
|
44259
|
+
|
|
44260
|
+
// name the chord set to include filtering information
|
|
44261
|
+
const encodedName = this.name.replaceAll(' ', '%20');
|
|
44262
|
+
const chordSetName = "all" === refFrame.chr ?
|
|
44263
|
+
encodedName :
|
|
44264
|
+
`${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end} ; range:${this.dataRange.min}-${this.dataRange.max})`;
|
|
44265
|
+
this.browser.circularView.addChords(chords, {track: chordSetName, color: chordSetColor, trackColor: trackColor});
|
|
44266
|
+
}
|
|
43615
44267
|
|
|
43616
44268
|
doAutoscale(features) {
|
|
43617
44269
|
|
|
@@ -43678,10 +44330,12 @@ class InteractionTrack extends TrackBase {
|
|
|
43678
44330
|
const featureList = features || clickState.viewport.getCachedFeatures();
|
|
43679
44331
|
const candidates = [];
|
|
43680
44332
|
if (featureList) {
|
|
43681
|
-
const proportional = this.arcType === "proportional";
|
|
44333
|
+
const proportional = (this.arcType === "proportional" || this.arcType === "inView" || this.arcType === "partialInView");
|
|
43682
44334
|
|
|
43683
44335
|
for (let feature of featureList) {
|
|
44336
|
+
|
|
43684
44337
|
if (!feature.drawState) continue
|
|
44338
|
+
|
|
43685
44339
|
if (feature.chr1 === feature.chr2 || feature.chr === 'all') {
|
|
43686
44340
|
if (proportional) {
|
|
43687
44341
|
//(x-xc)^2/radiusX^2 + (y-yc)^2/radiusY^2 <= 1
|
|
@@ -43719,6 +44373,26 @@ class InteractionTrack extends TrackBase {
|
|
|
43719
44373
|
}
|
|
43720
44374
|
return candidates.map((c) => c.feature)
|
|
43721
44375
|
}
|
|
44376
|
+
|
|
44377
|
+
/**
|
|
44378
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
44379
|
+
*
|
|
44380
|
+
* @returns {*|{}}
|
|
44381
|
+
*/
|
|
44382
|
+
getState() {
|
|
44383
|
+
|
|
44384
|
+
const config = super.getState();
|
|
44385
|
+
|
|
44386
|
+
// if (this.height !== undefined) config.height = this.height;
|
|
44387
|
+
if (this.arcType !== undefined) config.arcType = this.arcType;
|
|
44388
|
+
if (this.arcOrientation !== undefined) config.arcOrientation = this.arcOrientation;
|
|
44389
|
+
if (this.showBlocks !== undefined) config.showBlocks = this.showBlocks;
|
|
44390
|
+
if (this.blockHeight !== undefined) config.blockHeight = this.blockHeight;
|
|
44391
|
+
if (this.thickness !== undefined) config.thickness = this.thickness;
|
|
44392
|
+
if (this.alpha !== undefined) config.alpha = this.alpha;
|
|
44393
|
+
|
|
44394
|
+
return config
|
|
44395
|
+
}
|
|
43722
44396
|
}
|
|
43723
44397
|
|
|
43724
44398
|
function getMidpoints(feature, genome) {
|
|
@@ -43782,29 +44456,93 @@ function getAlphaColor(color, alpha) {
|
|
|
43782
44456
|
|
|
43783
44457
|
|
|
43784
44458
|
/**
|
|
43785
|
-
* Called in the context of FeatureSource
|
|
44459
|
+
* Called in the context of FeatureSource (i.e. this == the feature source (a TextFeatureSource) for the track
|
|
44460
|
+
*
|
|
43786
44461
|
* @param allFeatures
|
|
43787
44462
|
* @returns {[]}
|
|
43788
44463
|
*/
|
|
43789
44464
|
function getWGFeatures(allFeatures) {
|
|
43790
44465
|
|
|
44466
|
+
const makeWGFeature = (f) => {
|
|
44467
|
+
const wg = Object.assign({}, f);
|
|
44468
|
+
wg.chr = "all";
|
|
44469
|
+
wg.start = genome.getGenomeCoordinate(f.chr1, f.start1);
|
|
44470
|
+
wg.end = genome.getGenomeCoordinate(f.chr2, f.end2);
|
|
44471
|
+
return wg
|
|
44472
|
+
};
|
|
44473
|
+
|
|
43791
44474
|
const genome = this.genome;
|
|
43792
|
-
|
|
44475
|
+
|
|
44476
|
+
// First pass -- find the max score feature
|
|
44477
|
+
let maxScoreFeature;
|
|
44478
|
+
let totalFeatureCount = 0;
|
|
43793
44479
|
for (let c of genome.wgChromosomeNames) {
|
|
43794
|
-
|
|
44480
|
+
let chrFeatures = allFeatures[c];
|
|
43795
44481
|
if (chrFeatures) {
|
|
43796
44482
|
for (let f of chrFeatures) {
|
|
43797
44483
|
if (!f.dup) {
|
|
43798
|
-
|
|
43799
|
-
|
|
43800
|
-
|
|
43801
|
-
|
|
43802
|
-
|
|
44484
|
+
totalFeatureCount++;
|
|
44485
|
+
if (f.score && (!maxScoreFeature || f.score > maxScoreFeature.score)) {
|
|
44486
|
+
maxScoreFeature = f;
|
|
44487
|
+
}
|
|
44488
|
+
}
|
|
44489
|
+
}
|
|
44490
|
+
}
|
|
44491
|
+
}
|
|
44492
|
+
|
|
44493
|
+
const maxCount = this.maxWGCount;
|
|
44494
|
+
const nBins = maxScoreFeature && maxScoreFeature.score > 0 && totalFeatureCount > maxCount ? 5 : 1; // TODO make a function of total # of features & maxCount?
|
|
44495
|
+
const featuresPerBin = Math.floor(maxCount / nBins);
|
|
44496
|
+
const binSize = maxScoreFeature && maxScoreFeature.score > 0 ? Math.log(maxScoreFeature.score) / nBins : Number.MAX_SAFE_INTEGER;
|
|
44497
|
+
|
|
44498
|
+
let binnedFeatures = [];
|
|
44499
|
+
let counts = [];
|
|
44500
|
+
for (let i = 0; i < nBins; i++) {
|
|
44501
|
+
counts.push([0]);
|
|
44502
|
+
binnedFeatures.push([]);
|
|
44503
|
+
}
|
|
44504
|
+
|
|
44505
|
+
for (let c of genome.wgChromosomeNames) {
|
|
44506
|
+
let chrFeatures = allFeatures[c];
|
|
44507
|
+
if (chrFeatures) {
|
|
44508
|
+
for (let f of chrFeatures) {
|
|
44509
|
+
if (!f.dup) {
|
|
44510
|
+
const bin = f.score ? Math.min(nBins - 1, Math.floor(Math.log(f.score) / binSize)) : 0;
|
|
44511
|
+
if (binnedFeatures[bin].length < featuresPerBin) {
|
|
44512
|
+
binnedFeatures[bin].push(makeWGFeature(f));
|
|
44513
|
+
} else {
|
|
44514
|
+
//Reservoir sampling
|
|
44515
|
+
const samplingProb = featuresPerBin / (counts[bin] + 1);
|
|
44516
|
+
if (Math.random() < samplingProb) {
|
|
44517
|
+
const idx = Math.floor(Math.random() * (featuresPerBin - 1));
|
|
44518
|
+
binnedFeatures[bin][idx] = makeWGFeature(f);
|
|
44519
|
+
}
|
|
44520
|
+
}
|
|
44521
|
+
counts[bin]++;
|
|
43803
44522
|
}
|
|
43804
44523
|
}
|
|
43805
44524
|
}
|
|
43806
44525
|
}
|
|
43807
44526
|
|
|
44527
|
+
let wgFeatures;
|
|
44528
|
+
if (nBins === 1) {
|
|
44529
|
+
wgFeatures = binnedFeatures[0];
|
|
44530
|
+
} else {
|
|
44531
|
+
wgFeatures = [];
|
|
44532
|
+
for (let bf of binnedFeatures) {
|
|
44533
|
+
for (let f of bf) wgFeatures.push(f);
|
|
44534
|
+
}
|
|
44535
|
+
// Keep the feature with max score
|
|
44536
|
+
if (maxScoreFeature) {
|
|
44537
|
+
wgFeatures.push(makeWGFeature(maxScoreFeature));
|
|
44538
|
+
}
|
|
44539
|
+
wgFeatures.sort(function (a, b) {
|
|
44540
|
+
return a.start - b.start
|
|
44541
|
+
});
|
|
44542
|
+
console.log(wgFeatures.length);
|
|
44543
|
+
}
|
|
44544
|
+
|
|
44545
|
+
|
|
43808
44546
|
return wgFeatures
|
|
43809
44547
|
}
|
|
43810
44548
|
|
|
@@ -44876,7 +45614,6 @@ class GWASTrack extends TrackBase {
|
|
|
44876
45614
|
this.divider = config.divider || "rgb(225,225,225)";
|
|
44877
45615
|
this.dotSize = config.dotSize || 3;
|
|
44878
45616
|
this.popoverWindow = (config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow);
|
|
44879
|
-
this.description = config.description; // might be null
|
|
44880
45617
|
|
|
44881
45618
|
this.colorScales = config.color ?
|
|
44882
45619
|
new ConstantColorScale(config.color) :
|
|
@@ -46428,12 +47165,6 @@ class SpliceJunctionTrack extends TrackBase {
|
|
|
46428
47165
|
return data
|
|
46429
47166
|
}
|
|
46430
47167
|
|
|
46431
|
-
|
|
46432
|
-
description() {
|
|
46433
|
-
return this.name
|
|
46434
|
-
|
|
46435
|
-
}
|
|
46436
|
-
|
|
46437
47168
|
/**
|
|
46438
47169
|
* Called when the track is removed. Do any needed cleanup here
|
|
46439
47170
|
*/
|
|
@@ -47000,7 +47731,7 @@ class ReferenceFrame {
|
|
|
47000
47731
|
this.end = end;
|
|
47001
47732
|
|
|
47002
47733
|
this.bpPerPixel = bpPerPixel;
|
|
47003
|
-
this.id = guid$
|
|
47734
|
+
this.id = guid$2();
|
|
47004
47735
|
}
|
|
47005
47736
|
|
|
47006
47737
|
calculateEnd(pixels) {
|
|
@@ -47722,7 +48453,7 @@ class CursorGuide {
|
|
|
47722
48453
|
|
|
47723
48454
|
this.addMouseHandler(browser);
|
|
47724
48455
|
|
|
47725
|
-
this.setVisibility(browser.config.
|
|
48456
|
+
this.setVisibility(browser.config.showCursorGuide);
|
|
47726
48457
|
|
|
47727
48458
|
}
|
|
47728
48459
|
|
|
@@ -47739,35 +48470,40 @@ class CursorGuide {
|
|
|
47739
48470
|
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
47740
48471
|
|
|
47741
48472
|
let viewport = undefined;
|
|
47742
|
-
if (target.parentElement.classList.contains('igv-viewport-content')) {
|
|
47743
|
-
viewport = target.parentElement.parentElement;
|
|
47744
|
-
} else if (target.parentElement.classList.contains('igv-viewport') && target.classList.contains('igv-viewport-content')) {
|
|
47745
|
-
viewport = target.parentElement;
|
|
47746
|
-
}
|
|
47747
48473
|
|
|
47748
|
-
if (
|
|
48474
|
+
if (target.parentElement) {
|
|
47749
48475
|
|
|
47750
|
-
|
|
48476
|
+
if (target.parentElement.classList.contains('igv-viewport-content')) {
|
|
48477
|
+
viewport = target.parentElement.parentElement;
|
|
48478
|
+
} else if (target.parentElement.classList.contains('igv-viewport') && target.classList.contains('igv-viewport-content')) {
|
|
48479
|
+
viewport = target.parentElement;
|
|
48480
|
+
}
|
|
48481
|
+
|
|
48482
|
+
if (viewport && browser.getRulerTrackView()) {
|
|
48483
|
+
|
|
48484
|
+
this.verticalGuide.style.left = `${x}px`;
|
|
47751
48485
|
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
47755
|
-
|
|
47756
|
-
|
|
47757
|
-
|
|
48486
|
+
const columns = browser.root.querySelectorAll('.igv-column');
|
|
48487
|
+
let index = undefined;
|
|
48488
|
+
const viewportParent = viewport.parentElement;
|
|
48489
|
+
for (let i = 0; i < columns.length; i++) {
|
|
48490
|
+
if (undefined === index && viewportParent === columns[i]) {
|
|
48491
|
+
index = i;
|
|
48492
|
+
}
|
|
47758
48493
|
}
|
|
47759
|
-
}
|
|
47760
48494
|
|
|
47761
|
-
|
|
47762
|
-
|
|
48495
|
+
const rulerViewport = browser.getRulerTrackView().viewports[index];
|
|
48496
|
+
const result = rulerViewport.mouseMove(event);
|
|
47763
48497
|
|
|
47764
|
-
|
|
48498
|
+
if (result) {
|
|
47765
48499
|
|
|
47766
|
-
|
|
47767
|
-
|
|
48500
|
+
const {start, bp, end} = result;
|
|
48501
|
+
const interpolant = (bp - start) / (end - start);
|
|
48502
|
+
|
|
48503
|
+
if (this.customMouseHandler) {
|
|
48504
|
+
this.customMouseHandler({start, bp, end, interpolant});
|
|
48505
|
+
}
|
|
47768
48506
|
|
|
47769
|
-
if (this.customMouseHandler) {
|
|
47770
|
-
this.customMouseHandler({start, bp, end, interpolant});
|
|
47771
48507
|
}
|
|
47772
48508
|
|
|
47773
48509
|
}
|
|
@@ -47781,8 +48517,8 @@ class CursorGuide {
|
|
|
47781
48517
|
this.columnContainer.removeEventListener('mousemove', this.boundMouseMoveHandler);
|
|
47782
48518
|
}
|
|
47783
48519
|
|
|
47784
|
-
setVisibility(
|
|
47785
|
-
if (true ===
|
|
48520
|
+
setVisibility(showCursorGuide) {
|
|
48521
|
+
if (true === showCursorGuide) {
|
|
47786
48522
|
this.show();
|
|
47787
48523
|
} else {
|
|
47788
48524
|
this.hide();
|
|
@@ -47953,50 +48689,52 @@ class CenterLineButton {
|
|
|
47953
48689
|
* THE SOFTWARE.
|
|
47954
48690
|
*/
|
|
47955
48691
|
|
|
47956
|
-
|
|
48692
|
+
class TrackLabelControl {
|
|
47957
48693
|
|
|
47958
|
-
|
|
47959
|
-
parent.appendChild(this.button);
|
|
47960
|
-
this.button.textContent = 'track labels';
|
|
48694
|
+
constructor(parent, browser) {
|
|
47961
48695
|
|
|
47962
|
-
|
|
47963
|
-
|
|
47964
|
-
this.
|
|
47965
|
-
browser.setTrackLabelVisibility(browser.trackLabelsVisible);
|
|
47966
|
-
});
|
|
48696
|
+
this.button = div$1({class: 'igv-navbar-button'});
|
|
48697
|
+
parent.appendChild(this.button);
|
|
48698
|
+
this.button.textContent = 'track labels';
|
|
47967
48699
|
|
|
47968
|
-
|
|
48700
|
+
this.button.addEventListener('click', () => {
|
|
48701
|
+
browser.trackLabelsVisible = !browser.trackLabelsVisible;
|
|
48702
|
+
this.setState(browser.trackLabelsVisible);
|
|
48703
|
+
browser.setTrackLabelVisibility(browser.trackLabelsVisible);
|
|
48704
|
+
});
|
|
47969
48705
|
|
|
47970
|
-
|
|
48706
|
+
this.browser = browser;
|
|
47971
48707
|
|
|
47972
|
-
|
|
48708
|
+
this.setVisibility(browser.config.showTrackLabelButton);
|
|
47973
48709
|
|
|
47974
|
-
|
|
48710
|
+
this.setState(browser.trackLabelsVisible);
|
|
48711
|
+
}
|
|
47975
48712
|
|
|
47976
|
-
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
47980
|
-
|
|
48713
|
+
setVisibility(showTrackLabelButton) {
|
|
48714
|
+
if (true === showTrackLabelButton) {
|
|
48715
|
+
this.show();
|
|
48716
|
+
} else {
|
|
48717
|
+
this.hide();
|
|
48718
|
+
}
|
|
47981
48719
|
}
|
|
47982
|
-
};
|
|
47983
48720
|
|
|
47984
|
-
|
|
47985
|
-
|
|
47986
|
-
|
|
47987
|
-
|
|
47988
|
-
|
|
48721
|
+
setState(trackLabelsVisible) {
|
|
48722
|
+
if (true === trackLabelsVisible) {
|
|
48723
|
+
this.button.classList.add('igv-navbar-button-clicked');
|
|
48724
|
+
} else {
|
|
48725
|
+
this.button.classList.remove('igv-navbar-button-clicked');
|
|
48726
|
+
}
|
|
47989
48727
|
}
|
|
47990
|
-
};
|
|
47991
48728
|
|
|
47992
|
-
|
|
47993
|
-
|
|
47994
|
-
|
|
47995
|
-
}
|
|
48729
|
+
show() {
|
|
48730
|
+
this.button.style.display = 'block';
|
|
48731
|
+
this.setState(this.browser.trackLabelsVisible);
|
|
48732
|
+
}
|
|
47996
48733
|
|
|
47997
|
-
|
|
47998
|
-
|
|
47999
|
-
}
|
|
48734
|
+
hide() {
|
|
48735
|
+
this.button.style.display = 'none';
|
|
48736
|
+
}
|
|
48737
|
+
}
|
|
48000
48738
|
|
|
48001
48739
|
/*
|
|
48002
48740
|
* The MIT License (MIT)
|
|
@@ -48281,55 +49019,6 @@ const SVGSaveControl = function (parent, browser) {
|
|
|
48281
49019
|
button.addEventListener('click', () => browser.saveSVGtoFile({}));
|
|
48282
49020
|
};
|
|
48283
49021
|
|
|
48284
|
-
const viewportColumnManager =
|
|
48285
|
-
{
|
|
48286
|
-
createColumns: (columnContainer, count) => {
|
|
48287
|
-
|
|
48288
|
-
for (let i = 0; i < count; i++) {
|
|
48289
|
-
if (0 === i) {
|
|
48290
|
-
createColumn(columnContainer, 'igv-column');
|
|
48291
|
-
} else {
|
|
48292
|
-
columnContainer.appendChild(div$1({class: 'igv-column-shim'}));
|
|
48293
|
-
createColumn(columnContainer, 'igv-column');
|
|
48294
|
-
}
|
|
48295
|
-
}
|
|
48296
|
-
|
|
48297
|
-
},
|
|
48298
|
-
|
|
48299
|
-
removeColumnAtIndex: (i, column) => {
|
|
48300
|
-
const shim = 0 === i ? column.nextElementSibling : column.previousElementSibling;
|
|
48301
|
-
column.remove();
|
|
48302
|
-
shim.remove();
|
|
48303
|
-
},
|
|
48304
|
-
|
|
48305
|
-
insertAfter: referenceElement => {
|
|
48306
|
-
|
|
48307
|
-
const shim = div$1({class: 'igv-column-shim'});
|
|
48308
|
-
insertElementAfter(shim, referenceElement);
|
|
48309
|
-
|
|
48310
|
-
const column = div$1({class: 'igv-column'});
|
|
48311
|
-
insertElementAfter(column, shim);
|
|
48312
|
-
|
|
48313
|
-
return column
|
|
48314
|
-
},
|
|
48315
|
-
|
|
48316
|
-
insertBefore: (referenceElement, count) => {
|
|
48317
|
-
|
|
48318
|
-
for (let i = 0; i < count; i++) {
|
|
48319
|
-
|
|
48320
|
-
const column = div$1({class: 'igv-column'});
|
|
48321
|
-
insertElementBefore(column, referenceElement);
|
|
48322
|
-
|
|
48323
|
-
if (count > 1 && i > 0) {
|
|
48324
|
-
const columnShim = div$1({class: 'igv-column-shim'});
|
|
48325
|
-
insertElementBefore(columnShim, column);
|
|
48326
|
-
}
|
|
48327
|
-
|
|
48328
|
-
}
|
|
48329
|
-
|
|
48330
|
-
},
|
|
48331
|
-
};
|
|
48332
|
-
|
|
48333
49022
|
/*
|
|
48334
49023
|
* The MIT License (MIT)
|
|
48335
49024
|
*
|
|
@@ -48711,6 +49400,18 @@ CircularViewControl.prototype.hide = function () {
|
|
|
48711
49400
|
this.button.style.display = 'none';
|
|
48712
49401
|
};
|
|
48713
49402
|
|
|
49403
|
+
/**
|
|
49404
|
+
* User supplied button for the navbar
|
|
49405
|
+
*/
|
|
49406
|
+
|
|
49407
|
+
const CustomButton = function (parent, browser, b) {
|
|
49408
|
+
|
|
49409
|
+
const button = div$1({class: 'igv-navbar-button'});
|
|
49410
|
+
parent.append(button);
|
|
49411
|
+
button.textContent = b.label;
|
|
49412
|
+
button.addEventListener('click', () => b.callback(browser));
|
|
49413
|
+
};
|
|
49414
|
+
|
|
48714
49415
|
/*
|
|
48715
49416
|
* The MIT License (MIT)
|
|
48716
49417
|
*
|
|
@@ -48756,7 +49457,7 @@ class Browser {
|
|
|
48756
49457
|
constructor(config, parentDiv) {
|
|
48757
49458
|
|
|
48758
49459
|
this.config = config;
|
|
48759
|
-
this.guid = guid$
|
|
49460
|
+
this.guid = guid$2();
|
|
48760
49461
|
this.namespace = '.browser_' + this.guid;
|
|
48761
49462
|
|
|
48762
49463
|
this.parent = parentDiv;
|
|
@@ -48808,7 +49509,7 @@ class Browser {
|
|
|
48808
49509
|
|
|
48809
49510
|
this.isCenterLineVisible = config.showCenterGuide;
|
|
48810
49511
|
|
|
48811
|
-
this.cursorGuideVisible = config.
|
|
49512
|
+
this.cursorGuideVisible = config.showCursorGuide;
|
|
48812
49513
|
|
|
48813
49514
|
this.showSampleNames = config.showSampleNames;
|
|
48814
49515
|
this.showSampleNameButton = config.showSampleNameButton;
|
|
@@ -48921,6 +49622,12 @@ class Browser {
|
|
|
48921
49622
|
this.svgSaveControl = new SVGSaveControl($toggle_button_container.get(0), this);
|
|
48922
49623
|
}
|
|
48923
49624
|
|
|
49625
|
+
if(config.customButtons) {
|
|
49626
|
+
for(let b of config.customButtons) {
|
|
49627
|
+
new CustomButton($toggle_button_container.get(0), this, b);
|
|
49628
|
+
}
|
|
49629
|
+
}
|
|
49630
|
+
|
|
48924
49631
|
this.zoomWidget = new ZoomWidget(this, $navbarRightContainer.get(0));
|
|
48925
49632
|
|
|
48926
49633
|
if (false === config.showNavigation) {
|
|
@@ -48928,13 +49635,13 @@ class Browser {
|
|
|
48928
49635
|
}
|
|
48929
49636
|
|
|
48930
49637
|
this.inputDialog = new InputDialog(this.root);
|
|
48931
|
-
this.inputDialog.container.id = `igv-input-dialog-${guid$
|
|
49638
|
+
this.inputDialog.container.id = `igv-input-dialog-${guid$2()}`;
|
|
48932
49639
|
|
|
48933
49640
|
this.dataRangeDialog = new DataRangeDialog($$1(this.root));
|
|
48934
|
-
this.dataRangeDialog.$container.get(0).id = `igv-data-range-dialog-${guid$
|
|
49641
|
+
this.dataRangeDialog.$container.get(0).id = `igv-data-range-dialog-${guid$2()}`;
|
|
48935
49642
|
|
|
48936
49643
|
this.genericColorPicker = new GenericColorPicker({parent: this.columnContainer, width: 432});
|
|
48937
|
-
this.genericColorPicker.container.id = `igv-track-color-picker-${guid$
|
|
49644
|
+
this.genericColorPicker.container.id = `igv-track-color-picker-${guid$2()}`;
|
|
48938
49645
|
|
|
48939
49646
|
return $navBar
|
|
48940
49647
|
|
|
@@ -49963,46 +50670,6 @@ class Browser {
|
|
|
49963
50670
|
|
|
49964
50671
|
}
|
|
49965
50672
|
|
|
49966
|
-
async selectMultiLocusPanel(referenceFrame) {
|
|
49967
|
-
|
|
49968
|
-
const referenceFrameIndex = this.referenceFrameList.indexOf(referenceFrame);
|
|
49969
|
-
|
|
49970
|
-
// Remove columns for unselected panels
|
|
49971
|
-
this.columnContainer.querySelectorAll('.igv-column').forEach((column, c) => {
|
|
49972
|
-
if (c === referenceFrameIndex) ; else {
|
|
49973
|
-
|
|
49974
|
-
column.remove();
|
|
49975
|
-
}
|
|
49976
|
-
});
|
|
49977
|
-
|
|
49978
|
-
// Remove all column shims
|
|
49979
|
-
this.columnContainer.querySelectorAll('.igv-column-shim').forEach(shim => shim.remove());
|
|
49980
|
-
|
|
49981
|
-
// Discard viewports
|
|
49982
|
-
for (let trackView of this.trackViews) {
|
|
49983
|
-
|
|
49984
|
-
const retain = trackView.viewports[referenceFrameIndex];
|
|
49985
|
-
trackView.viewports.filter((viewport, i) => i !== referenceFrameIndex).forEach(viewport => viewport.dispose());
|
|
49986
|
-
trackView.viewports = [retain];
|
|
49987
|
-
|
|
49988
|
-
}
|
|
49989
|
-
|
|
49990
|
-
const viewportWidth = this.calculateViewportWidth(1);
|
|
49991
|
-
referenceFrame.bpPerPixel = (referenceFrame.end - referenceFrame.start) / viewportWidth;
|
|
49992
|
-
|
|
49993
|
-
this.referenceFrameList = [referenceFrame];
|
|
49994
|
-
|
|
49995
|
-
this.trackViews.forEach(({viewports}) => viewports.forEach(viewport => viewport.setWidth(viewportWidth)));
|
|
49996
|
-
|
|
49997
|
-
|
|
49998
|
-
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
49999
|
-
|
|
50000
|
-
this.updateUIWithReferenceFrameList();
|
|
50001
|
-
|
|
50002
|
-
await this.updateViews(true);
|
|
50003
|
-
|
|
50004
|
-
}
|
|
50005
|
-
|
|
50006
50673
|
async selectMultiLocusPanel(referenceFrame) {
|
|
50007
50674
|
|
|
50008
50675
|
const referenceFrameIndex = this.referenceFrameList.indexOf(referenceFrame);
|
|
@@ -50226,6 +50893,7 @@ class Browser {
|
|
|
50226
50893
|
// Build locus array (multi-locus view). Use the first track to extract the loci, any track could be used.
|
|
50227
50894
|
const locus = [];
|
|
50228
50895
|
const gtexSelections = {};
|
|
50896
|
+
let hasGtexSelections = false;
|
|
50229
50897
|
let anyTrackView = this.trackViews[0];
|
|
50230
50898
|
for (let {referenceFrame} of anyTrackView.viewports) {
|
|
50231
50899
|
const locusString = referenceFrame.getLocusString();
|
|
@@ -50236,12 +50904,11 @@ class Browser {
|
|
|
50236
50904
|
snp: referenceFrame.selection.snp
|
|
50237
50905
|
};
|
|
50238
50906
|
gtexSelections[locusString] = selection;
|
|
50907
|
+
hasGtexSelections = true;
|
|
50239
50908
|
}
|
|
50240
50909
|
}
|
|
50241
50910
|
json["locus"] = locus.length === 1 ? locus[0] : locus;
|
|
50242
|
-
|
|
50243
|
-
const gtexKeys = Object.getOwnPropertyNames(gtexSelections);
|
|
50244
|
-
if (gtexKeys.length > 0) {
|
|
50911
|
+
if (hasGtexSelections) {
|
|
50245
50912
|
json["gtexSelections"] = gtexSelections;
|
|
50246
50913
|
}
|
|
50247
50914
|
|
|
@@ -50265,27 +50932,21 @@ class Browser {
|
|
|
50265
50932
|
trackJson.push(config);
|
|
50266
50933
|
}
|
|
50267
50934
|
} catch (e) {
|
|
50268
|
-
|
|
50935
|
+
console.error(`Track: ${track.name}: ${e}`);
|
|
50936
|
+
errors.push(`Track: ${track.name}: ${e}`);
|
|
50269
50937
|
}
|
|
50270
50938
|
}
|
|
50271
50939
|
|
|
50272
50940
|
if (errors.length > 0) {
|
|
50273
50941
|
let n = 1;
|
|
50274
|
-
let message = 'Errors encountered saving session:';
|
|
50942
|
+
let message = 'Errors encountered saving session: </br>';
|
|
50275
50943
|
for (let e of errors) {
|
|
50276
|
-
message += ` (${n++}) ${e.toString()}
|
|
50944
|
+
message += ` (${n++}) ${e.toString()} <br/>`;
|
|
50277
50945
|
}
|
|
50278
50946
|
throw Error(message)
|
|
50279
50947
|
}
|
|
50280
50948
|
|
|
50281
50949
|
|
|
50282
|
-
const locaTrackFiles = trackJson.filter((track) => {
|
|
50283
|
-
track.url && isFile(track.url);
|
|
50284
|
-
});
|
|
50285
|
-
|
|
50286
|
-
if (locaTrackFiles.length > 0) {
|
|
50287
|
-
throw new Error(`Error. Sessions cannot include local file references.`)
|
|
50288
|
-
}
|
|
50289
50950
|
|
|
50290
50951
|
json["tracks"] = trackJson;
|
|
50291
50952
|
|
|
@@ -50673,7 +51334,7 @@ async function createBrowser(parentDiv, config) {
|
|
|
50673
51334
|
|
|
50674
51335
|
setDefaults(config);
|
|
50675
51336
|
|
|
50676
|
-
if (config.queryParametersSupported
|
|
51337
|
+
if (config.queryParametersSupported) {
|
|
50677
51338
|
extractQuery(config);
|
|
50678
51339
|
}
|
|
50679
51340
|
if (config.apiKey) {
|
|
@@ -50737,10 +51398,6 @@ async function visibilityChange() {
|
|
|
50737
51398
|
|
|
50738
51399
|
function setDefaults(config) {
|
|
50739
51400
|
|
|
50740
|
-
if (undefined === config.promisified) {
|
|
50741
|
-
config.promisified = false;
|
|
50742
|
-
}
|
|
50743
|
-
|
|
50744
51401
|
if (undefined === config.minimumBases) {
|
|
50745
51402
|
config.minimumBases = 40;
|
|
50746
51403
|
}
|
|
@@ -50769,8 +51426,9 @@ function setDefaults(config) {
|
|
|
50769
51426
|
config.showCursorTrackingGuideButton = true;
|
|
50770
51427
|
}
|
|
50771
51428
|
|
|
50772
|
-
|
|
50773
|
-
|
|
51429
|
+
|
|
51430
|
+
if (undefined === config.showCursorGuide) {
|
|
51431
|
+
config.showCursorGuide = config.showCursorTrackingGuide || false; // showCursorTrackingGuide is a synonym
|
|
50774
51432
|
}
|
|
50775
51433
|
|
|
50776
51434
|
if (undefined === config.showCenterGuideButton) {
|
|
@@ -50861,6 +51519,8 @@ function extractQuery(config) {
|
|
|
50861
51519
|
config[key] = value;
|
|
50862
51520
|
}
|
|
50863
51521
|
i = j + 1;
|
|
51522
|
+
} else {
|
|
51523
|
+
i++;
|
|
50864
51524
|
}
|
|
50865
51525
|
}
|
|
50866
51526
|
}
|
|
@@ -50897,7 +51557,7 @@ async function createTrack(config, browser) {
|
|
|
50897
51557
|
|
|
50898
51558
|
function embedCSS() {
|
|
50899
51559
|
|
|
50900
|
-
var css = '.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3; }\n .igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px; }\n .igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 210px;\n height: 22px;\n line-height: 22px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none; }\n .igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div {\n margin-left: 0;\n margin-right: 4px; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div:last-child {\n margin-left: 0;\n margin-right: 0; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-750 {\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none; }\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px; }\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373; }\n\n.igv-navbar-button:hover {\n cursor: pointer; }\n\n.igv-zoom-in-notice-container {\n z-index: 1024;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white; }\n .igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f; }\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%; }\n .igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64; }\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373; }\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 14px;\n height: 14px;\n color: #666666;\n background-color: white;\n z-index: 1000; }\n .igv-multi-locus-close-button > svg {\n vertical-align: top; }\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343; }\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 14px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-multi-locus-ruler-label div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #101010;\n background-color: white; }\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px; }\n .igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #101010; }\n\n.igv-multi-locus-ruler-label:hover {\n cursor: pointer; }\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25); }\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737; }\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 200px;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer; }\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8; }\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin; }\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51); }\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0); }\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 1;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76); }\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 1;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none; }\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent; }\n .igv-user-feedback div:first-child div:first-child {\n left: 8px; }\n .igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px; }\n .igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0; }\n .igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px; }\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px; }\n .igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd; }\n .igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px; }\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n z-index: 4096;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left; }\n .igv-menu-popup > div:not(:first-child) {\n width: 100%; }\n .igv-menu-popup > div:not(:first-child) > div {\n background: white; }\n .igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px; }\n .igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef; }\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px; }\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444; }\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n background-color: transparent; }\n .igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px; }\n .igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px; }\n .igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px; }\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent; }\n .igv-user-feedback div:first-child div:first-child {\n left: 8px; }\n .igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px; }\n .igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0; }\n .igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px; }\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: white;\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite; }\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg); } }\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg); } }\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none; }\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n overflow-x: hidden;\n overflow-y: hidden; }\n\n.igv-viewport-content {\n position: relative;\n width: 100%; }\n .igv-viewport-content > canvas {\n position: relative;\n display: block; }\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%; }\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453; }\n\n.igv-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%; }\n\n.igv-axis-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px; }\n .igv-axis-column > div {\n margin-top: 5px;\n width: 100%; }\n\n.igv-sample-name-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%; }\n\n.igv-scrollbar-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px; }\n .igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px; }\n .igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px; }\n .igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4; }\n\n.igv-track-drag-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white; }\n .igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n background-color: #c4c4c4; }\n .igv-track-drag-column .igv-track-drag-handle-hover {\n background-color: #787878; }\n .igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0; }\n\n.igv-gear-menu-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px; }\n .igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white; }\n .igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F; }\n .igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444; }\n\n/*# sourceMappingURL=dom.css.map */\n';
|
|
51560
|
+
var css = '.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3; }\n .igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px; }\n .igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 210px;\n height: 22px;\n line-height: 22px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px; }\n .igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none; }\n .igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div {\n margin-left: 0;\n margin-right: 4px; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div:last-child {\n margin-left: 0;\n margin-right: 0; }\n .igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-750 {\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block; }\n .igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none; }\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px; }\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373; }\n\n.igv-navbar-button:hover {\n cursor: pointer; }\n\n.igv-zoom-in-notice-container {\n z-index: 1024;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white; }\n .igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f; }\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%; }\n .igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64; }\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373; }\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 18px;\n height: 18px;\n color: #666666;\n background-color: white;\n z-index: 1000; }\n .igv-multi-locus-close-button > svg {\n vertical-align: top; }\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343; }\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 14px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-multi-locus-ruler-label div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #101010;\n background-color: white; }\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px; }\n .igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #101010; }\n\n.igv-multi-locus-ruler-label:hover {\n cursor: pointer; }\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25); }\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737; }\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 200px;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer; }\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8; }\n\n.igv-track-label-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-top: 4px; }\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin; }\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51); }\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0); }\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 1;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76); }\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 1;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none; }\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent; }\n .igv-user-feedback div:first-child div:first-child {\n left: 8px; }\n .igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px; }\n .igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0; }\n .igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px; }\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px; }\n .igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd; }\n .igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px; }\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n z-index: 4096;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left; }\n .igv-menu-popup > div:not(:first-child) {\n width: 100%; }\n .igv-menu-popup > div:not(:first-child) > div {\n background: white; }\n .igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px; }\n .igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef; }\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-bottom: 1px;\n padding-top: 1px; }\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center; }\n .igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444; }\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n margin-right: 4px;\n background-color: transparent; }\n .igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px; }\n .igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px; }\n .igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px; }\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin; }\n .igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent; }\n .igv-user-feedback div:first-child div:first-child {\n left: 8px; }\n .igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px; }\n .igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0; }\n .igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px; }\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: white;\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite; }\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg); } }\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg); } }\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none; }\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n overflow-x: hidden;\n overflow-y: hidden; }\n\n.igv-viewport-content {\n position: relative;\n width: 100%; }\n .igv-viewport-content > canvas {\n position: relative;\n display: block; }\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%; }\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453; }\n\n.igv-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%; }\n\n.igv-axis-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px; }\n .igv-axis-column > div {\n margin-top: 5px;\n width: 100%; }\n\n.igv-sample-name-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%; }\n\n.igv-scrollbar-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px; }\n .igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px; }\n .igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px; }\n .igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4; }\n\n.igv-track-drag-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white; }\n .igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n background-color: #c4c4c4; }\n .igv-track-drag-column .igv-track-drag-handle-hover {\n background-color: #787878; }\n .igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0; }\n\n.igv-gear-menu-column {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px; }\n .igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white; }\n .igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F; }\n .igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444; }\n\n/*# sourceMappingURL=dom.css.map */\n';
|
|
50901
51561
|
|
|
50902
51562
|
var style = document.createElement('style');
|
|
50903
51563
|
style.setAttribute('type', 'text/css');
|