igv 2.10.5 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/igv.esm.js +1703 -1046
- package/dist/igv.esm.min.js +6 -6
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +2057 -1335
- 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: 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 -webkit-user-select: all;\n -moz-user-select: all;\n -ms-user-select: all;\n user-select: all;\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');
|
|
@@ -19897,6 +19899,218 @@ function translateDeprecatedTypes(config) {
|
|
|
19897
19899
|
}
|
|
19898
19900
|
}
|
|
19899
19901
|
|
|
19902
|
+
/*
|
|
19903
|
+
* The MIT License (MIT)
|
|
19904
|
+
*
|
|
19905
|
+
* Copyright (c) 2014 Broad Institute
|
|
19906
|
+
*
|
|
19907
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19908
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
19909
|
+
* in the Software without restriction, including without limitation the rights
|
|
19910
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19911
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19912
|
+
* furnished to do so, subject to the following conditions:
|
|
19913
|
+
*
|
|
19914
|
+
* The above copyright notice and this permission notice shall be included in
|
|
19915
|
+
* all copies or substantial portions of the Software.
|
|
19916
|
+
*
|
|
19917
|
+
*
|
|
19918
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19919
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19920
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19921
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19922
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19923
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19924
|
+
* THE SOFTWARE.
|
|
19925
|
+
*/
|
|
19926
|
+
|
|
19927
|
+
/**
|
|
19928
|
+
* Test if the given value is a string or number. Not using typeof as it fails on boxed primitives.
|
|
19929
|
+
*
|
|
19930
|
+
* @param value
|
|
19931
|
+
* @returns boolean
|
|
19932
|
+
*/
|
|
19933
|
+
|
|
19934
|
+
function isSimpleType(value) {
|
|
19935
|
+
const simpleTypes = new Set(["boolean", "number", "string", "symbol"]);
|
|
19936
|
+
const valueType = typeof value;
|
|
19937
|
+
return (value !== undefined && (simpleTypes.has(valueType) || value.substring || value.toFixed))
|
|
19938
|
+
}
|
|
19939
|
+
|
|
19940
|
+
function buildOptions(config, options) {
|
|
19941
|
+
|
|
19942
|
+
var defaultOptions = {
|
|
19943
|
+
oauthToken: config.oauthToken,
|
|
19944
|
+
headers: config.headers,
|
|
19945
|
+
withCredentials: config.withCredentials,
|
|
19946
|
+
filename: config.filename
|
|
19947
|
+
};
|
|
19948
|
+
|
|
19949
|
+
return Object.assign(defaultOptions, options)
|
|
19950
|
+
}
|
|
19951
|
+
|
|
19952
|
+
/**
|
|
19953
|
+
* isMobile test from http://detectmobilebrowsers.com
|
|
19954
|
+
* TODO -- improve UI design so this isn't neccessary
|
|
19955
|
+
* @returns {boolean}
|
|
19956
|
+
*/
|
|
19957
|
+
|
|
19958
|
+
// igv.isMobile = function () {
|
|
19959
|
+
//
|
|
19960
|
+
// const a = (navigator.userAgent || navigator.vendor || window.opera);
|
|
19961
|
+
// 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) ||
|
|
19962
|
+
// /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)))
|
|
19963
|
+
//
|
|
19964
|
+
// }
|
|
19965
|
+
|
|
19966
|
+
const doAutoscale = function (features) {
|
|
19967
|
+
var min, max;
|
|
19968
|
+
|
|
19969
|
+
if (features.length > 0) {
|
|
19970
|
+
min = Number.MAX_VALUE;
|
|
19971
|
+
max = -Number.MAX_VALUE;
|
|
19972
|
+
|
|
19973
|
+
features.forEach(function (f) {
|
|
19974
|
+
if (!Number.isNaN(f.value)) {
|
|
19975
|
+
min = Math.min(min, f.value);
|
|
19976
|
+
max = Math.max(max, f.value);
|
|
19977
|
+
}
|
|
19978
|
+
});
|
|
19979
|
+
|
|
19980
|
+
// Insure we have a zero baseline
|
|
19981
|
+
if (max > 0) min = Math.min(0, min);
|
|
19982
|
+
if (max < 0) max = 0;
|
|
19983
|
+
} else {
|
|
19984
|
+
// No features -- default
|
|
19985
|
+
min = 0;
|
|
19986
|
+
max = 100;
|
|
19987
|
+
}
|
|
19988
|
+
|
|
19989
|
+
return {min: min, max: max}
|
|
19990
|
+
};
|
|
19991
|
+
|
|
19992
|
+
const validateLocusExtent = function (chromosomeLengthBP, extent, minimumBP) {
|
|
19993
|
+
|
|
19994
|
+
let ss = extent.start;
|
|
19995
|
+
let ee = extent.end;
|
|
19996
|
+
|
|
19997
|
+
if (undefined === ee) {
|
|
19998
|
+
|
|
19999
|
+
ss -= minimumBP / 2;
|
|
20000
|
+
ee = ss + minimumBP;
|
|
20001
|
+
|
|
20002
|
+
if (ee > chromosomeLengthBP) {
|
|
20003
|
+
ee = chromosomeLengthBP;
|
|
20004
|
+
ss = ee - minimumBP;
|
|
20005
|
+
} else if (ss < 0) {
|
|
20006
|
+
ss = 0;
|
|
20007
|
+
ee = minimumBP;
|
|
20008
|
+
}
|
|
20009
|
+
|
|
20010
|
+
} else if (ee - ss < minimumBP) {
|
|
20011
|
+
|
|
20012
|
+
const center = (ee + ss) / 2;
|
|
20013
|
+
|
|
20014
|
+
if (center - minimumBP / 2 < 0) {
|
|
20015
|
+
ss = 0;
|
|
20016
|
+
ee = ss + minimumBP;
|
|
20017
|
+
} else if (center + minimumBP / 2 > chromosomeLengthBP) {
|
|
20018
|
+
ee = chromosomeLengthBP;
|
|
20019
|
+
ss = ee - minimumBP;
|
|
20020
|
+
} else {
|
|
20021
|
+
ss = center - minimumBP / 2;
|
|
20022
|
+
ee = ss + minimumBP;
|
|
20023
|
+
}
|
|
20024
|
+
}
|
|
20025
|
+
|
|
20026
|
+
extent.start = Math.ceil(ss);
|
|
20027
|
+
extent.end = Math.floor(ee);
|
|
20028
|
+
};
|
|
20029
|
+
|
|
20030
|
+
/*!
|
|
20031
|
+
* is-number <https://github.com/jonschlinkert/is-number>
|
|
20032
|
+
*
|
|
20033
|
+
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
20034
|
+
* Released under the MIT License.
|
|
20035
|
+
*/
|
|
20036
|
+
|
|
20037
|
+
const isNumber = function (num) {
|
|
20038
|
+
if (typeof num === 'number') {
|
|
20039
|
+
return num - num === 0
|
|
20040
|
+
}
|
|
20041
|
+
if (typeof num === 'string' && num.trim() !== '') {
|
|
20042
|
+
return Number.isFinite ? Number.isFinite(+num) : isFinite(+num)
|
|
20043
|
+
}
|
|
20044
|
+
return false
|
|
20045
|
+
};
|
|
20046
|
+
|
|
20047
|
+
async function getFilename(url) {
|
|
20048
|
+
if (isString$3(url) && url.startsWith("https://drive.google.com")) {
|
|
20049
|
+
// This will fail if Google API key is not defined
|
|
20050
|
+
if (getApiKey() === undefined) {
|
|
20051
|
+
throw Error("Google drive is referenced, but API key is not defined. An API key is required for Google Drive access")
|
|
20052
|
+
}
|
|
20053
|
+
const json = await getDriveFileInfo(url);
|
|
20054
|
+
return json.originalFileName || json.name
|
|
20055
|
+
} else {
|
|
20056
|
+
return getFilename$1(url)
|
|
20057
|
+
}
|
|
20058
|
+
}
|
|
20059
|
+
|
|
20060
|
+
function prettyBasePairNumber(raw) {
|
|
20061
|
+
|
|
20062
|
+
var denom,
|
|
20063
|
+
units,
|
|
20064
|
+
value,
|
|
20065
|
+
floored;
|
|
20066
|
+
|
|
20067
|
+
if (raw > 1e7) {
|
|
20068
|
+
denom = 1e6;
|
|
20069
|
+
units = " mb";
|
|
20070
|
+
} else if (raw > 1e4) {
|
|
20071
|
+
|
|
20072
|
+
denom = 1e3;
|
|
20073
|
+
units = " kb";
|
|
20074
|
+
|
|
20075
|
+
value = raw / denom;
|
|
20076
|
+
floored = Math.floor(value);
|
|
20077
|
+
return numberFormatter$1(floored) + units
|
|
20078
|
+
} else {
|
|
20079
|
+
return numberFormatter$1(raw) + " bp"
|
|
20080
|
+
}
|
|
20081
|
+
|
|
20082
|
+
value = raw / denom;
|
|
20083
|
+
floored = Math.floor(value);
|
|
20084
|
+
|
|
20085
|
+
return floored.toString() + units
|
|
20086
|
+
}
|
|
20087
|
+
|
|
20088
|
+
|
|
20089
|
+
function isDataURL(obj) {
|
|
20090
|
+
return (isString$3(obj) && obj.startsWith("data:"))
|
|
20091
|
+
}
|
|
20092
|
+
|
|
20093
|
+
function createColumn(columnContainer, className) {
|
|
20094
|
+
const column = div$1({class: className});
|
|
20095
|
+
columnContainer.appendChild(column);
|
|
20096
|
+
}
|
|
20097
|
+
|
|
20098
|
+
|
|
20099
|
+
function insertElementBefore(element, referenceNode) {
|
|
20100
|
+
referenceNode.parentNode.insertBefore(element, referenceNode);
|
|
20101
|
+
}
|
|
20102
|
+
|
|
20103
|
+
function insertElementAfter(element, referenceNode) {
|
|
20104
|
+
referenceNode.parentNode.insertBefore(element, referenceNode.nextSibling);
|
|
20105
|
+
}
|
|
20106
|
+
|
|
20107
|
+
/**
|
|
20108
|
+
* Test to see if page is loaded in a secure context, that is by https or is localhost.
|
|
20109
|
+
*/
|
|
20110
|
+
function isSecureContext() {
|
|
20111
|
+
return window.location.protocol === "https:" || window.location.hostname === "localhost"
|
|
20112
|
+
}
|
|
20113
|
+
|
|
19900
20114
|
/*
|
|
19901
20115
|
* The MIT License (MIT)
|
|
19902
20116
|
*
|
|
@@ -20275,7 +20489,7 @@ class Viewport {
|
|
|
20275
20489
|
|
|
20276
20490
|
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
20277
20491
|
|
|
20278
|
-
this.guid = guid$
|
|
20492
|
+
this.guid = guid$2();
|
|
20279
20493
|
this.trackView = trackView;
|
|
20280
20494
|
this.referenceFrame = referenceFrame;
|
|
20281
20495
|
|
|
@@ -22054,7 +22268,7 @@ GenomicInterval.prototype.containsRange = function (range) {
|
|
|
22054
22268
|
|
|
22055
22269
|
const splitLines$3 = splitLines$5;
|
|
22056
22270
|
|
|
22057
|
-
const reservedProperties = new Set(['fastaURL', 'indexURL', 'cytobandURL', 'indexed']);
|
|
22271
|
+
const reservedProperties = new Set(['fastaURL', 'indexURL', 'compressedIndexURL', 'cytobandURL', 'indexed']);
|
|
22058
22272
|
|
|
22059
22273
|
class FastaSequence {
|
|
22060
22274
|
|
|
@@ -22062,6 +22276,7 @@ class FastaSequence {
|
|
|
22062
22276
|
|
|
22063
22277
|
this.file = reference.fastaURL;
|
|
22064
22278
|
this.indexFile = reference.indexURL || reference.indexFile || this.file + ".fai";
|
|
22279
|
+
this.compressedIndexFile = reference.compressedIndexURL || false;
|
|
22065
22280
|
this.withCredentials = reference.withCredentials;
|
|
22066
22281
|
this.chromosomeNames = [];
|
|
22067
22282
|
this.chromosomes = {};
|
|
@@ -22147,77 +22362,292 @@ class FastaSequence {
|
|
|
22147
22362
|
}
|
|
22148
22363
|
}
|
|
22149
22364
|
|
|
22150
|
-
async readSequence(chr, qstart, qend) {
|
|
22151
22365
|
|
|
22152
|
-
|
|
22153
|
-
|
|
22154
|
-
|
|
22155
|
-
|
|
22156
|
-
|
|
22366
|
+
//Code is losely based on https://github.com/GMOD/bgzf-filehandle
|
|
22367
|
+
//Reworked however in orde to work with the igvxhr interface for loading files
|
|
22368
|
+
//Additionally, replaced calls to the Long.js interface with standard JS calls for ArrayBuffers and the associated views
|
|
22369
|
+
//
|
|
22370
|
+
//The compressed index is an array of blocks, with each block being a pair: compressed-position & uncompressed-position (both in bytes)
|
|
22371
|
+
async getCompressedIndex() {
|
|
22372
|
+
const GZI_NUM_BYTES_OFFSET = 8;
|
|
22373
|
+
const GZI_NUM_BYTES_BLOCK = 8;
|
|
22374
|
+
if (this.compressedIndex) {
|
|
22375
|
+
return this.compressedIndex
|
|
22376
|
+
}
|
|
22377
|
+
if (!this.compressedIndexFile) {
|
|
22378
|
+
this.compressedIndex = [];
|
|
22379
|
+
return this.compressedIndex
|
|
22380
|
+
}
|
|
22381
|
+
//In contrast to the 'normal' reference (for which the index is chromosome based), this index is block-based
|
|
22382
|
+
//As such there is not need to make it a hash. An array is sufficient.
|
|
22383
|
+
this.compressedIndex = [];
|
|
22384
|
+
const gziData = await igvxhr.loadArrayBuffer(this.compressedIndexFile, buildOptions(this.config));
|
|
22385
|
+
const givenFileSize = gziData.byteLength;
|
|
22386
|
+
if (givenFileSize < GZI_NUM_BYTES_OFFSET) {
|
|
22387
|
+
console.log("Cannot parse GZI index file: length (" + givenFileSize + " bytes) is insufficient to determine content of index.");
|
|
22388
|
+
return this.compressedIndex
|
|
22389
|
+
}
|
|
22390
|
+
//First 8 bytes are a little endian unsigned bigint (64bit), indicating the number of blocks in the index.
|
|
22391
|
+
const numBlocksBuffer = gziData.slice(0, GZI_NUM_BYTES_OFFSET);
|
|
22392
|
+
const numBlocks = Number((new DataView(numBlocksBuffer)).getBigUint64(0, true));
|
|
22393
|
+
//The remainder of the gzi content are pairs of little endian unsigned bigint (64bit) numbers.
|
|
22394
|
+
//The first of the pair is the compressed position of a block
|
|
22395
|
+
//The second of the pair is the uncompressed position of a block
|
|
22396
|
+
|
|
22397
|
+
//Sanity check:
|
|
22398
|
+
//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?
|
|
22399
|
+
//Total file-size should be:
|
|
22400
|
+
// 8 + 2*(num_entries*8) bytes, with the first 8 bytes indicating the number of entries
|
|
22401
|
+
const expectedFileSize = GZI_NUM_BYTES_OFFSET + numBlocks * 2 * GZI_NUM_BYTES_BLOCK;
|
|
22402
|
+
if (givenFileSize != expectedFileSize) {
|
|
22403
|
+
console.log("Incorrect file size of reference genome index. Expected : " + expectedFileSize + ". Received : " + givenFileSize);
|
|
22404
|
+
return this.compressedIndex
|
|
22405
|
+
}
|
|
22406
|
+
|
|
22407
|
+
//Push the first block to the index: the first block always has positions 0 for both the compressed and uncompressed file
|
|
22408
|
+
this.compressedIndex.push([0, 0]);
|
|
22409
|
+
|
|
22410
|
+
//Further process all the blocks of the GZI index, and keep them in memory
|
|
22411
|
+
for (let blockNumber = 0; blockNumber < numBlocks; blockNumber++) {
|
|
22412
|
+
const bufferBlockStart = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK;
|
|
22413
|
+
const bufferBlockEnd = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK + 2 * GZI_NUM_BYTES_BLOCK;
|
|
22414
|
+
const bufferBlock = gziData.slice(bufferBlockStart, bufferBlockEnd);
|
|
22415
|
+
const viewBlock = new DataView(bufferBlock);
|
|
22416
|
+
const compressedPosition = Number(viewBlock.getBigUint64(0, true)); //First 8 bytes
|
|
22417
|
+
const uncompressedPosition = Number(viewBlock.getBigUint64(GZI_NUM_BYTES_BLOCK, true)); //Last 8 bytes
|
|
22418
|
+
this.compressedIndex.push([compressedPosition, uncompressedPosition]);
|
|
22419
|
+
}
|
|
22420
|
+
return this.compressedIndex
|
|
22421
|
+
}
|
|
22422
|
+
|
|
22423
|
+
//The Fasta-index gives a byte-position of the chromosomal sequences within the FASTA file.
|
|
22424
|
+
//These locations need to be remapped to the locations within the zipped reference genome, using the GZI index
|
|
22425
|
+
//This function provides this functionality by
|
|
22426
|
+
//1) taking the indicated start/stop byte locations within the UNCOMPRESSED FASTA file
|
|
22427
|
+
//2) remapping these byte locations to the correct blocks (and associated positions) within the COMPRESSED FASTA file
|
|
22428
|
+
//Subsequently, the calling method can then extract the correct blocks from the compressed FASTA files and uncompressed the data
|
|
22429
|
+
async getRelevantCompressedBlockNumbers(queryPositionStart, queryPositionEnd) {
|
|
22430
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
22431
|
+
//Fallback for impossible values
|
|
22432
|
+
if (queryPositionStart < 0 || queryPositionEnd < 0 || queryPositionEnd < queryPositionStart) {
|
|
22433
|
+
console.log("Incompatible query positions for reference-genome. Start:" + queryPositionStart + " | End:" + queryPositionEnd);
|
|
22434
|
+
return []
|
|
22435
|
+
}
|
|
22436
|
+
//Ensure compressed index is loaded
|
|
22437
|
+
await this.getCompressedIndex();
|
|
22438
|
+
let result = [];
|
|
22439
|
+
//Now search for the correct block-numbers (going from 0 to length(compressed-index)) which overlap with the provided byte-positions
|
|
22440
|
+
const lowestBlockNumber = 0;
|
|
22441
|
+
const highestBlockNumber = this.compressedIndex.length - 1;
|
|
22442
|
+
//Failsafe if for some reason the compressed index wasn't loaded or doesn't contain any data
|
|
22443
|
+
if (this.compressedIndex.length == 0) {
|
|
22444
|
+
console.log("Compressed index does not contain any content");
|
|
22445
|
+
return []
|
|
22446
|
+
}
|
|
22447
|
+
//Failsafe: if the queryPositionStart is greater than the uncompressed-position of the final block,
|
|
22448
|
+
//then this final block is the only possible result
|
|
22449
|
+
if (queryPositionStart > (this.compressedIndex)[highestBlockNumber][UNCOMPRESSED_POSITION]) {
|
|
22450
|
+
return [highestBlockNumber]
|
|
22451
|
+
}
|
|
22452
|
+
|
|
22453
|
+
//Rather than doing a linear search over all blocks, a binary search is done for speed considerations
|
|
22454
|
+
//We are searching for the highest block number for which its position is smaller than the query start position
|
|
22455
|
+
//Afterwards we will simply expand the blocks until the entire query range is covered
|
|
22456
|
+
let searchLow = lowestBlockNumber;
|
|
22457
|
+
let searchHigh = highestBlockNumber;
|
|
22458
|
+
let searchPosition = Math.floor(this.compressedIndex.length / 2);
|
|
22459
|
+
let maxIterations = this.compressedIndex.length + 1;
|
|
22460
|
+
let solutionFound = false;
|
|
22461
|
+
//instead of doing a while(true), this for-loop prevents eternal loops in case of issues
|
|
22462
|
+
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
22463
|
+
const searchUncompressedPosition = (this.compressedIndex)[searchPosition][UNCOMPRESSED_POSITION];
|
|
22464
|
+
const nextSearchUncompressedPosition = (searchPosition < (this.compressedIndex.length - 1)) ? (this.compressedIndex)[searchPosition + 1][UNCOMPRESSED_POSITION] : Infinity;
|
|
22465
|
+
//The query position lies within the current search block
|
|
22466
|
+
if (searchUncompressedPosition <= queryPositionStart && nextSearchUncompressedPosition > queryPositionStart) {
|
|
22467
|
+
solutionFound = true;
|
|
22468
|
+
break //searchPosition is the correct block number index
|
|
22469
|
+
}
|
|
22470
|
+
//Current block lies before the query position
|
|
22471
|
+
else if (searchUncompressedPosition < queryPositionStart) {
|
|
22472
|
+
searchLow = searchPosition + 1;
|
|
22473
|
+
}
|
|
22474
|
+
//Current block lies after the query position
|
|
22475
|
+
else {
|
|
22476
|
+
searchHigh = searchPosition - 1;
|
|
22477
|
+
}
|
|
22478
|
+
searchPosition = Math.ceil((searchHigh - searchLow) / 2) + searchLow;
|
|
22479
|
+
}
|
|
22480
|
+
//If for some reason the binary search did not reveal a correct block index, then we return the empty result
|
|
22481
|
+
if (!solutionFound) {
|
|
22482
|
+
console.log("No blocks within compressed index found that correspond with query positions " + queryPositionStart + "," + queryPositionEnd);
|
|
22483
|
+
console.log(this.compressedIndex);
|
|
22484
|
+
return []
|
|
22485
|
+
}
|
|
22486
|
+
|
|
22487
|
+
//Now extend the result by adding additional blocks until the entire query range is covered
|
|
22488
|
+
result.push(searchPosition);
|
|
22489
|
+
for (let blockIndex = searchPosition + 1; blockIndex < this.compressedIndex.length; blockIndex++) {
|
|
22490
|
+
result.push(blockIndex);
|
|
22491
|
+
const blockUncompressedPosition = (this.compressedIndex)[blockIndex][UNCOMPRESSED_POSITION];
|
|
22492
|
+
if (blockUncompressedPosition >= queryPositionEnd) {
|
|
22493
|
+
break
|
|
22494
|
+
}
|
|
22495
|
+
}
|
|
22496
|
+
|
|
22497
|
+
//It is possible that the query end position lies AFTER the start of the final block
|
|
22498
|
+
//If this is the case, we add a 'fake' negative index which will be interpreted by the loadAndUncompressBlocks method as an indicator
|
|
22499
|
+
//to read until the end of the file
|
|
22500
|
+
const finalRelevantBlock = result[result.length - 1];
|
|
22501
|
+
const finalIndexBlock = this.compressedIndex.length - 1;
|
|
22502
|
+
if (finalRelevantBlock === finalIndexBlock && (this.compressedIndex)[finalRelevantBlock][UNCOMPRESSED_POSITION] < queryPositionEnd) {
|
|
22503
|
+
result.push(-1);
|
|
22504
|
+
}
|
|
22505
|
+
|
|
22506
|
+
return result
|
|
22507
|
+
}
|
|
22508
|
+
|
|
22509
|
+
|
|
22510
|
+
//Load the content from the blockIndices.
|
|
22511
|
+
//This is done on a per-block basis
|
|
22512
|
+
//Content of the first block will be trimmed in order to match the expected offset
|
|
22513
|
+
async loadAndUncompressBlocks(blockIndices, startByte) {
|
|
22514
|
+
const COMPRESSED_POSITION = 0;
|
|
22515
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
22516
|
+
//Normally the compressed index should already exist, we're just makeing sure here
|
|
22517
|
+
await this.getCompressedIndex();
|
|
22518
|
+
|
|
22519
|
+
if (blockIndices.length == 0) {
|
|
22520
|
+
return ""
|
|
22521
|
+
}
|
|
22522
|
+
|
|
22523
|
+
//Storing data in seperate array with indices in order to assert order due to async behaviour of loops
|
|
22524
|
+
let resultCache = Array(blockIndices.length - 1);
|
|
22525
|
+
for (let i = 0; i < blockIndices.length - 1; i++) {
|
|
22526
|
+
const currentBlockNumber = blockIndices[i];
|
|
22527
|
+
const currentBlockInfo = (this.compressedIndex)[currentBlockNumber];
|
|
22528
|
+
const currentBlockCompressedPosition = currentBlockInfo[COMPRESSED_POSITION];
|
|
22529
|
+
|
|
22530
|
+
const nextBlockNumber = blockIndices[i + 1];
|
|
22531
|
+
let compressedBytes = [];
|
|
22532
|
+
if (nextBlockNumber != -1) { //default : read current entire block only
|
|
22533
|
+
const nextBlockInfo = (this.compressedIndex)[nextBlockNumber];
|
|
22534
|
+
const nextBlockCompressedPosition = nextBlockInfo[COMPRESSED_POSITION];
|
|
22535
|
+
const compressedLength = nextBlockCompressedPosition - currentBlockCompressedPosition;
|
|
22536
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
22537
|
+
range: {
|
|
22538
|
+
start: currentBlockCompressedPosition,
|
|
22539
|
+
size: compressedLength
|
|
22540
|
+
}
|
|
22541
|
+
}));
|
|
22542
|
+
} else { // special case for query within final block: read until the end of the file
|
|
22543
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
22544
|
+
range: {
|
|
22545
|
+
start: currentBlockCompressedPosition
|
|
22546
|
+
}
|
|
22547
|
+
}));
|
|
22548
|
+
}
|
|
22549
|
+
//now unzip the compressed bytes, and store them in the resultCache
|
|
22550
|
+
const uncompressedBytes = await unbgzf(compressedBytes);
|
|
22551
|
+
resultCache[i] = uncompressedBytes;
|
|
22552
|
+
}
|
|
22553
|
+
|
|
22554
|
+
//Iterate over the result cache, create sequences from the data, and create a full sequence string from the data
|
|
22555
|
+
let result = "";
|
|
22556
|
+
for (let i = 0; i < resultCache.length; i++) {
|
|
22557
|
+
for (let j = 0; j < resultCache[i].length; j++) {
|
|
22558
|
+
const c = String.fromCharCode(resultCache[i][j]);
|
|
22559
|
+
result = result + c;
|
|
22560
|
+
}
|
|
22561
|
+
}
|
|
22562
|
+
|
|
22563
|
+
//postprocess this data: because entire blocks are read we need to remove the first N bases of the first used block,
|
|
22564
|
+
//which are not included in the original query positions
|
|
22565
|
+
const firstBlockInfo = (this.compressedIndex)[blockIndices[0]];
|
|
22566
|
+
const offset = startByte - firstBlockInfo[UNCOMPRESSED_POSITION];
|
|
22567
|
+
result = result.substring(offset);
|
|
22568
|
+
|
|
22569
|
+
return result
|
|
22570
|
+
}
|
|
22571
|
+
|
|
22572
|
+
|
|
22573
|
+
async readSequence(chr, qstart, qend) {
|
|
22157
22574
|
|
|
22158
22575
|
await this.getIndex();
|
|
22576
|
+
await this.getCompressedIndex(); //This will work even if no compressed index file is set
|
|
22159
22577
|
|
|
22160
22578
|
const idxEntry = this.index[chr];
|
|
22161
22579
|
if (!idxEntry) {
|
|
22162
22580
|
console.log("No index entry for chr: " + chr);
|
|
22163
|
-
|
|
22164
22581
|
// Tag interval with null so we don't try again
|
|
22165
22582
|
this.interval = new GenomicInterval(chr, qstart, qend, null);
|
|
22166
22583
|
return null
|
|
22584
|
+
}
|
|
22167
22585
|
|
|
22168
|
-
|
|
22586
|
+
const start = Math.max(0, qstart); // qstart should never be < 0
|
|
22587
|
+
const end = Math.min(idxEntry.size, qend);
|
|
22588
|
+
const bytesPerLine = idxEntry.bytesPerLine;
|
|
22589
|
+
const basesPerLine = idxEntry.basesPerLine;
|
|
22590
|
+
const position = idxEntry.position;
|
|
22591
|
+
const nEndBytes = bytesPerLine - basesPerLine;
|
|
22592
|
+
const startLine = Math.floor(start / basesPerLine);
|
|
22593
|
+
const endLine = Math.floor(end / basesPerLine);
|
|
22594
|
+
const base0 = startLine * basesPerLine; // Base at beginning of start line
|
|
22595
|
+
const offset = start - base0;
|
|
22596
|
+
const startByte = position + startLine * bytesPerLine + offset;
|
|
22597
|
+
const base1 = endLine * basesPerLine;
|
|
22598
|
+
const offset1 = end - base1;
|
|
22599
|
+
const endByte = position + endLine * bytesPerLine + offset1 - 1;
|
|
22600
|
+
const byteCount = endByte - startByte + 1;
|
|
22601
|
+
|
|
22602
|
+
if (byteCount <= 0) {
|
|
22603
|
+
console.error("No sequence for " + chr + ":" + qstart + "-" + qend);
|
|
22604
|
+
return null
|
|
22605
|
+
}
|
|
22169
22606
|
|
|
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
|
-
}));
|
|
22607
|
+
//If the compressed index file is set, then we are dealing with a compressed genome sequence
|
|
22608
|
+
//The selection of startByte/endByte is done for the non-compressed genome sequence.
|
|
22609
|
+
//These need to be 'converted' to the correct byte positions in the compressed genome sequence,
|
|
22610
|
+
//by making use of the compressed index (GZI file)
|
|
22611
|
+
let allBytes;
|
|
22612
|
+
if (!this.compressedIndexFile) {
|
|
22613
|
+
allBytes = await igvxhr.load(this.file, buildOptions(this.config, {
|
|
22614
|
+
range: {
|
|
22615
|
+
start: startByte,
|
|
22616
|
+
size: byteCount
|
|
22617
|
+
}
|
|
22618
|
+
}));
|
|
22619
|
+
} else {
|
|
22620
|
+
let relevantBlockIndices = await this.getRelevantCompressedBlockNumbers(startByte, endByte);
|
|
22621
|
+
if (relevantBlockIndices.length === 0) {
|
|
22622
|
+
console.log("No blocks in the compressed index that correspond with the requested byte positions (" + startByte + "," + endByte + ")");
|
|
22623
|
+
return null
|
|
22196
22624
|
}
|
|
22625
|
+
allBytes = await this.loadAndUncompressBlocks(relevantBlockIndices, startByte);
|
|
22626
|
+
}
|
|
22197
22627
|
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
let nBases,
|
|
22202
|
-
seqBytes = "",
|
|
22203
|
-
srcPos = 0,
|
|
22204
|
-
allBytesLength = allBytes.length;
|
|
22628
|
+
if (!allBytes) {
|
|
22629
|
+
return null
|
|
22630
|
+
}
|
|
22205
22631
|
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
}
|
|
22632
|
+
let nBases,
|
|
22633
|
+
seqBytes = "",
|
|
22634
|
+
srcPos = 0,
|
|
22635
|
+
allBytesLength = allBytes.length;
|
|
22211
22636
|
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22637
|
+
if (offset > 0) {
|
|
22638
|
+
nBases = Math.min(end - start, basesPerLine - offset);
|
|
22639
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
22640
|
+
srcPos += (nBases + nEndBytes);
|
|
22641
|
+
}
|
|
22217
22642
|
|
|
22218
|
-
|
|
22219
|
-
|
|
22643
|
+
while (srcPos < allBytesLength) {
|
|
22644
|
+
nBases = Math.min(basesPerLine, allBytesLength - srcPos);
|
|
22645
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
22646
|
+
srcPos += (nBases + nEndBytes);
|
|
22220
22647
|
}
|
|
22648
|
+
|
|
22649
|
+
return seqBytes
|
|
22650
|
+
|
|
22221
22651
|
}
|
|
22222
22652
|
}
|
|
22223
22653
|
|
|
@@ -22329,7 +22759,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
22329
22759
|
}
|
|
22330
22760
|
};
|
|
22331
22761
|
|
|
22332
|
-
const _version = "2.
|
|
22762
|
+
const _version = "2.11.0";
|
|
22333
22763
|
function version() {
|
|
22334
22764
|
return _version
|
|
22335
22765
|
}
|
|
@@ -22856,7 +23286,9 @@ class TrackViewport extends Viewport {
|
|
|
22856
23286
|
}
|
|
22857
23287
|
|
|
22858
23288
|
stopSpinner() {
|
|
22859
|
-
this.$spinner
|
|
23289
|
+
if (this.$spinner) {
|
|
23290
|
+
this.$spinner.hide();
|
|
23291
|
+
}
|
|
22860
23292
|
}
|
|
22861
23293
|
|
|
22862
23294
|
checkZoomIn() {
|
|
@@ -23183,7 +23615,7 @@ class TrackViewport extends Viewport {
|
|
|
23183
23615
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23184
23616
|
|
|
23185
23617
|
const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
|
|
23186
|
-
const id = `${str}_referenceFrame_${index}_guid_${guid$
|
|
23618
|
+
const id = `${str}_referenceFrame_${index}_guid_${guid$2()}`;
|
|
23187
23619
|
|
|
23188
23620
|
this.drawSVGWithContext(context, width, height, id, 0, 0, 0);
|
|
23189
23621
|
|
|
@@ -23206,7 +23638,7 @@ class TrackViewport extends Viewport {
|
|
|
23206
23638
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23207
23639
|
|
|
23208
23640
|
const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
|
|
23209
|
-
const id = `${str}_referenceFrame_${index}_guid_${guid$
|
|
23641
|
+
const id = `${str}_referenceFrame_${index}_guid_${guid$2()}`;
|
|
23210
23642
|
|
|
23211
23643
|
const {top: yScrollDelta} = this.$content.position();
|
|
23212
23644
|
|
|
@@ -23225,7 +23657,7 @@ class TrackViewport extends Viewport {
|
|
|
23225
23657
|
renderTrackLabelSVG(context, tx, ty, width, height) {
|
|
23226
23658
|
|
|
23227
23659
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
23228
|
-
const id = `${str}_track_label_guid_${guid$
|
|
23660
|
+
const id = `${str}_track_label_guid_${guid$2()}`;
|
|
23229
23661
|
|
|
23230
23662
|
context.saveWithTranslationAndClipRect(id, tx, ty, width, height, 0);
|
|
23231
23663
|
|
|
@@ -23552,28 +23984,16 @@ class TrackViewport extends Viewport {
|
|
|
23552
23984
|
str = track.description();
|
|
23553
23985
|
} else if (track.description) {
|
|
23554
23986
|
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
23987
|
}
|
|
23567
23988
|
|
|
23568
|
-
if (
|
|
23569
|
-
this.popover
|
|
23989
|
+
if (str) {
|
|
23990
|
+
if (this.popover) {
|
|
23991
|
+
this.popover.dispose();
|
|
23992
|
+
}
|
|
23993
|
+
this.popover = new Popover(this.browser.columnContainer, (track.name || ''));
|
|
23994
|
+
this.popover.presentContentWithEvent(event, str);
|
|
23570
23995
|
}
|
|
23571
|
-
|
|
23572
|
-
this.popover = new Popover(this.browser.columnContainer, (track.name || 'unnamed'));
|
|
23573
|
-
|
|
23574
|
-
this.popover.presentContentWithEvent(event, str);
|
|
23575
23996
|
}
|
|
23576
|
-
|
|
23577
23997
|
}
|
|
23578
23998
|
|
|
23579
23999
|
removeTrackLabelClickHandler(trackLabel) {
|
|
@@ -28743,7 +29163,7 @@ class TrackBase {
|
|
|
28743
29163
|
this.config = config;
|
|
28744
29164
|
this.url = config.url;
|
|
28745
29165
|
this.type = config.type;
|
|
28746
|
-
|
|
29166
|
+
|
|
28747
29167
|
this.supportHiDPI = config.supportHiDPI === undefined ? true : config.supportHiDPI;
|
|
28748
29168
|
|
|
28749
29169
|
if (config.name || config.label) {
|
|
@@ -28781,6 +29201,15 @@ class TrackBase {
|
|
|
28781
29201
|
this.onclick = config.onclick;
|
|
28782
29202
|
config.onclick = undefined; // functions cannot be saved in sessions, clear it here.
|
|
28783
29203
|
}
|
|
29204
|
+
|
|
29205
|
+
if (config.description) {
|
|
29206
|
+
// Override description -- displayed when clicking on track label. Convert to function if neccessary
|
|
29207
|
+
if (typeof config.description === 'function') {
|
|
29208
|
+
this.description = config.description;
|
|
29209
|
+
} else {
|
|
29210
|
+
this.description = () => config.description;
|
|
29211
|
+
}
|
|
29212
|
+
}
|
|
28784
29213
|
}
|
|
28785
29214
|
|
|
28786
29215
|
get name() {
|
|
@@ -28823,7 +29252,7 @@ class TrackBase {
|
|
|
28823
29252
|
for (let key of Object.keys(state)) {
|
|
28824
29253
|
if (key.startsWith("_")) continue // transient property
|
|
28825
29254
|
const value = this[key];
|
|
28826
|
-
if (value && (isSimpleType(value) || typeof value === "boolean")) {
|
|
29255
|
+
if (value && (isSimpleType(value) || typeof value === "boolean" || key === "metadata")) {
|
|
28827
29256
|
state[key] = value;
|
|
28828
29257
|
}
|
|
28829
29258
|
}
|
|
@@ -28837,16 +29266,18 @@ class TrackBase {
|
|
|
28837
29266
|
state.max = this.dataRange.max;
|
|
28838
29267
|
}
|
|
28839
29268
|
|
|
29269
|
+
|
|
28840
29270
|
// Check for non-json-if-yable properties. Perhaps we should test what can be saved.
|
|
28841
29271
|
for (let key of Object.keys(state)) {
|
|
28842
|
-
|
|
29272
|
+
const value = state[key];
|
|
29273
|
+
if (typeof value === 'function') {
|
|
28843
29274
|
throw Error(`Property '${key}' of track '${this.name} is a function. Functions cannot be saved in sessions.`)
|
|
28844
29275
|
}
|
|
28845
|
-
if (
|
|
29276
|
+
if (value instanceof File) { // Test specifically for File. Other types of File-like objects might be savable
|
|
28846
29277
|
const str = `Track ${this.name} is a local file. Sessions cannot be saved with local file references.`;
|
|
28847
29278
|
throw Error(str)
|
|
28848
29279
|
}
|
|
28849
|
-
if (
|
|
29280
|
+
if (value instanceof Promise) {
|
|
28850
29281
|
throw Error(`Property '${key}' of track '${this.name} is a Promise. Promises cannot be saved in sessions.`)
|
|
28851
29282
|
}
|
|
28852
29283
|
}
|
|
@@ -29092,6 +29523,49 @@ class TrackBase {
|
|
|
29092
29523
|
|
|
29093
29524
|
}
|
|
29094
29525
|
|
|
29526
|
+
/**
|
|
29527
|
+
* Default track description -- displayed on click of track label. This can be overriden in the track
|
|
29528
|
+
* configuration, or in subclasses.
|
|
29529
|
+
*/
|
|
29530
|
+
description() {
|
|
29531
|
+
|
|
29532
|
+
const wrapKeyValue = (k, v) => `<div class="igv-track-label-popup-shim"><b>${k}: </b>${v}</div>`;
|
|
29533
|
+
|
|
29534
|
+
let str = '<div class="igv-track-label-popup">';
|
|
29535
|
+
if (this.url) {
|
|
29536
|
+
if (isFile(this.url)) {
|
|
29537
|
+
str += wrapKeyValue('Filename', this.url.name);
|
|
29538
|
+
} else {
|
|
29539
|
+
str += wrapKeyValue('URL', this.url);
|
|
29540
|
+
}
|
|
29541
|
+
} else {
|
|
29542
|
+
str = this.name;
|
|
29543
|
+
}
|
|
29544
|
+
if (this.config) {
|
|
29545
|
+
if (this.config.metadata) {
|
|
29546
|
+
for (let key of Object.keys(this.config.metadata)) {
|
|
29547
|
+
const value = this.config.metadata[key];
|
|
29548
|
+
str += wrapKeyValue(key, value);
|
|
29549
|
+
}
|
|
29550
|
+
}
|
|
29551
|
+
|
|
29552
|
+
// Add any config properties that are capitalized
|
|
29553
|
+
for (let key of Object.keys(this.config)) {
|
|
29554
|
+
if (key.startsWith("_")) continue // transient property
|
|
29555
|
+
let first = key.substr(0, 1);
|
|
29556
|
+
if (first !== first.toLowerCase()) {
|
|
29557
|
+
const value = this.config[key];
|
|
29558
|
+
if (value && isSimpleType(value)) {
|
|
29559
|
+
str += wrapKeyValue(key, value);
|
|
29560
|
+
}
|
|
29561
|
+
}
|
|
29562
|
+
}
|
|
29563
|
+
|
|
29564
|
+
}
|
|
29565
|
+
str += '</div>';
|
|
29566
|
+
return str
|
|
29567
|
+
}
|
|
29568
|
+
|
|
29095
29569
|
static getCravatLink(chr, position, ref, alt, genomeID) {
|
|
29096
29570
|
|
|
29097
29571
|
if ("hg38" === genomeID || "GRCh38" === genomeID) {
|
|
@@ -29138,6 +29612,8 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29138
29612
|
return
|
|
29139
29613
|
}
|
|
29140
29614
|
|
|
29615
|
+
let flipAxis = (undefined === this.flipAxis) ? false : this.flipAxis;
|
|
29616
|
+
|
|
29141
29617
|
IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
29142
29618
|
|
|
29143
29619
|
reference = 0.95 * pixelWidth;
|
|
@@ -29152,7 +29628,7 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29152
29628
|
|
|
29153
29629
|
// tick
|
|
29154
29630
|
IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font);
|
|
29155
|
-
IGVGraphics.fillText(ctx, prettyPrint(this.dataRange.max), x1 + 4, y1 + 12, font);
|
|
29631
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.min : this.dataRange.max), x1 + 4, y1 + 12, font);
|
|
29156
29632
|
|
|
29157
29633
|
//shim = 0.25 * 0.125;
|
|
29158
29634
|
y1 = y2 = (1.0 - shim) * pixelHeight;
|
|
@@ -29161,7 +29637,7 @@ function paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
|
29161
29637
|
|
|
29162
29638
|
// tick
|
|
29163
29639
|
IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font);
|
|
29164
|
-
IGVGraphics.fillText(ctx, prettyPrint(this.dataRange.min), x1 + 4, y1 - 4, font);
|
|
29640
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max : this.dataRange.min), x1 + 4, y1 - 4, font);
|
|
29165
29641
|
|
|
29166
29642
|
IGVGraphics.strokeLine(ctx, a.x, a.y, b.x, b.y, font);
|
|
29167
29643
|
|
|
@@ -30566,6 +31042,75 @@ const chrColorMap$1 = {
|
|
|
30566
31042
|
"chr48": "rgb(20, 255, 177)",
|
|
30567
31043
|
};
|
|
30568
31044
|
|
|
31045
|
+
class ChordSetManager {
|
|
31046
|
+
|
|
31047
|
+
constructor(config) {
|
|
31048
|
+
this.tracks = [];
|
|
31049
|
+
this.chordSets = [];
|
|
31050
|
+
}
|
|
31051
|
+
|
|
31052
|
+
addChordSet(chordSet) {
|
|
31053
|
+
|
|
31054
|
+
// If a chord set with this name exists replace it (same track, same region)
|
|
31055
|
+
this.chordSets = this.chordSets.filter(g => g.name !== chordSet.name);
|
|
31056
|
+
this.chordSets.push(chordSet);
|
|
31057
|
+
|
|
31058
|
+
let track = this.tracks.find(t => chordSet.trackName === t.name);
|
|
31059
|
+
if (track) {
|
|
31060
|
+
track.chordSets = track.chordSets.filter(cs => cs.name !== chordSet.name);
|
|
31061
|
+
track.chordSets.push(chordSet);
|
|
31062
|
+
}
|
|
31063
|
+
if (!track) {
|
|
31064
|
+
track = new IGVTrack(chordSet);
|
|
31065
|
+
this.tracks.push(track);
|
|
31066
|
+
}
|
|
31067
|
+
}
|
|
31068
|
+
|
|
31069
|
+
clearChords() {
|
|
31070
|
+
this.tracks = [];
|
|
31071
|
+
this.chordSets = [];
|
|
31072
|
+
}
|
|
31073
|
+
|
|
31074
|
+
getTrack(name) {
|
|
31075
|
+
return this.tracks.find(t => name === t.name)
|
|
31076
|
+
}
|
|
31077
|
+
|
|
31078
|
+
getChordset(name) {
|
|
31079
|
+
return this.chordSets.find(cs => name === cs.name)
|
|
31080
|
+
}
|
|
31081
|
+
|
|
31082
|
+
}
|
|
31083
|
+
|
|
31084
|
+
class IGVTrack {
|
|
31085
|
+
constructor(chordSet) {
|
|
31086
|
+
this.name = chordSet.trackName;
|
|
31087
|
+
this.color = chordSet.trackColor;
|
|
31088
|
+
this.visible = true;
|
|
31089
|
+
this.chordSets = [chordSet];
|
|
31090
|
+
this.id = guid$1();
|
|
31091
|
+
}
|
|
31092
|
+
|
|
31093
|
+
get chords() {
|
|
31094
|
+
if (this.chordSets.length === 1) {
|
|
31095
|
+
return this.chordSets[0].chords
|
|
31096
|
+
}
|
|
31097
|
+
const chords = [];
|
|
31098
|
+
for (let cs of this.chordSets) {
|
|
31099
|
+
for (let c of cs.chords) {
|
|
31100
|
+
chords.push(c);
|
|
31101
|
+
}
|
|
31102
|
+
}
|
|
31103
|
+
return chords
|
|
31104
|
+
}
|
|
31105
|
+
}
|
|
31106
|
+
|
|
31107
|
+
|
|
31108
|
+
function guid$1() {
|
|
31109
|
+
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
|
|
31110
|
+
}
|
|
31111
|
+
|
|
31112
|
+
const EXP5 = Math.exp(5);
|
|
31113
|
+
|
|
30569
31114
|
class CircularView {
|
|
30570
31115
|
|
|
30571
31116
|
static isInstalled() {
|
|
@@ -30590,6 +31135,8 @@ class CircularView {
|
|
|
30590
31135
|
if (CircularView.isInstalled()) {
|
|
30591
31136
|
|
|
30592
31137
|
this.parent = parent;
|
|
31138
|
+
this.groupByTrack = config.groupByTrack === true;
|
|
31139
|
+
this.chordManager = new ChordSetManager(config);
|
|
30593
31140
|
|
|
30594
31141
|
// wrapper for toolbar and circular-view container
|
|
30595
31142
|
const wrapper = document.createElement('div');
|
|
@@ -30597,7 +31144,8 @@ class CircularView {
|
|
|
30597
31144
|
parent.appendChild(wrapper);
|
|
30598
31145
|
|
|
30599
31146
|
// toolbar
|
|
30600
|
-
this.
|
|
31147
|
+
this.createControls(wrapper);
|
|
31148
|
+
this.resetControlPanel();
|
|
30601
31149
|
|
|
30602
31150
|
// circular view container
|
|
30603
31151
|
const element = document.createElement('div');
|
|
@@ -30609,8 +31157,6 @@ class CircularView {
|
|
|
30609
31157
|
this.setAssembly(config.assembly);
|
|
30610
31158
|
}
|
|
30611
31159
|
|
|
30612
|
-
this.tracks = config.tracks || [];
|
|
30613
|
-
|
|
30614
31160
|
this.width = config.width || 500;
|
|
30615
31161
|
this.height = config.height || 500;
|
|
30616
31162
|
this.setSize(this.width, this.height);
|
|
@@ -30620,55 +31166,47 @@ class CircularView {
|
|
|
30620
31166
|
}
|
|
30621
31167
|
}
|
|
30622
31168
|
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
let element;
|
|
31169
|
+
createControls(parent) {
|
|
30626
31170
|
|
|
30627
31171
|
// toolbar
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
parent.appendChild(
|
|
30631
|
-
this.toolbar =
|
|
31172
|
+
const toolbarDiv = document.createElement('div');
|
|
31173
|
+
toolbarDiv.className = 'igv-circview-toolbar';
|
|
31174
|
+
parent.appendChild(toolbarDiv);
|
|
31175
|
+
this.toolbar = toolbarDiv;
|
|
30632
31176
|
|
|
30633
|
-
|
|
30634
|
-
|
|
30635
|
-
|
|
30636
|
-
|
|
30637
|
-
|
|
30638
|
-
this.
|
|
30639
|
-
|
|
30640
|
-
this.trackPanel.style.display = 'none';
|
|
31177
|
+
// control panel
|
|
31178
|
+
const controlPanelDiv = document.createElement('div');
|
|
31179
|
+
controlPanelDiv.className = 'igv-circview-track-panel';
|
|
31180
|
+
parent.appendChild(controlPanelDiv);
|
|
31181
|
+
this.controlPanel = controlPanelDiv;
|
|
31182
|
+
this.controlPanel.style.display = 'none';
|
|
30641
31183
|
|
|
30642
31184
|
|
|
30643
31185
|
// toolbar button container - Track Options - Clear All
|
|
30644
|
-
|
|
31186
|
+
const buttonContainer = document.createElement('div');
|
|
30645
31187
|
buttonContainer.className = 'igv-circview-toolbar-button-container';
|
|
30646
31188
|
this.toolbar.appendChild(buttonContainer);
|
|
30647
31189
|
|
|
30648
|
-
//
|
|
30649
|
-
this.
|
|
30650
|
-
this.
|
|
30651
|
-
buttonContainer.appendChild(this.
|
|
30652
|
-
this.
|
|
30653
|
-
this.
|
|
30654
|
-
|
|
30655
|
-
const trackPanelRows = this.trackPanel.querySelectorAll('div');
|
|
30656
|
-
|
|
31190
|
+
// Show Controls
|
|
31191
|
+
this.showControlsButton = document.createElement('div');
|
|
31192
|
+
this.showControlsButton.className = 'igv-circview-button';
|
|
31193
|
+
buttonContainer.appendChild(this.showControlsButton);
|
|
31194
|
+
this.showControlsButton.innerText = 'none' === this.controlPanel.style.display ? 'Show Controls' : 'Hide Controls';
|
|
31195
|
+
this.showControlsButton.addEventListener('click', (event) => {
|
|
31196
|
+
const trackPanelRows = this.controlPanel.querySelectorAll('div');
|
|
30657
31197
|
if (trackPanelRows.length > 0) {
|
|
30658
31198
|
|
|
30659
|
-
if ('none' === this.
|
|
30660
|
-
this.
|
|
30661
|
-
event.target.innerText = 'Hide
|
|
31199
|
+
if ('none' === this.controlPanel.style.display) {
|
|
31200
|
+
this.controlPanel.style.display = 'flex';
|
|
31201
|
+
event.target.innerText = 'Hide Controls';
|
|
30662
31202
|
} else {
|
|
30663
|
-
this.
|
|
30664
|
-
event.target.innerText = 'Show
|
|
31203
|
+
this.controlPanel.style.display = 'none';
|
|
31204
|
+
event.target.innerText = 'Show Controls';
|
|
30665
31205
|
}
|
|
30666
|
-
|
|
30667
31206
|
}
|
|
30668
|
-
|
|
30669
31207
|
});
|
|
30670
31208
|
|
|
30671
|
-
// Clear All
|
|
31209
|
+
// Clear All
|
|
30672
31210
|
let button = document.createElement('div');
|
|
30673
31211
|
button.className = 'igv-circview-button';
|
|
30674
31212
|
buttonContainer.appendChild(button);
|
|
@@ -30677,14 +31215,8 @@ class CircularView {
|
|
|
30677
31215
|
this.clearChords();
|
|
30678
31216
|
});
|
|
30679
31217
|
|
|
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) {
|
|
31218
|
+
// Close
|
|
31219
|
+
if (false !== this.config.showCloseButton) {
|
|
30688
31220
|
button = document.createElement('div');
|
|
30689
31221
|
button.className = 'igv-circview-button';
|
|
30690
31222
|
buttonContainer.appendChild(button);
|
|
@@ -30693,60 +31225,115 @@ class CircularView {
|
|
|
30693
31225
|
this.visible = false;
|
|
30694
31226
|
});
|
|
30695
31227
|
}
|
|
31228
|
+
}
|
|
30696
31229
|
|
|
31230
|
+
resetControlPanel() {
|
|
31231
|
+
this.controlPanel.innerHTML = '';
|
|
31232
|
+
this.controlPanel.appendChild(this.createGroupByCB());
|
|
31233
|
+
const chordSets = this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets;
|
|
31234
|
+
for(let cs of chordSets) {
|
|
31235
|
+
this.addToControlPanel(cs);
|
|
31236
|
+
}
|
|
30697
31237
|
}
|
|
30698
31238
|
|
|
30699
|
-
|
|
31239
|
+
createGroupByCB() {
|
|
31240
|
+
const groupByCB = document.createElement('input');
|
|
31241
|
+
groupByCB.type = 'checkbox';
|
|
31242
|
+
groupByCB.id = 'groupByCB';
|
|
31243
|
+
groupByCB.style.width = '1.4em';
|
|
31244
|
+
groupByCB.style.height = '1.4em';
|
|
31245
|
+
groupByCB.checked = this.groupByTrack;
|
|
30700
31246
|
|
|
30701
|
-
|
|
31247
|
+
groupByCB.onclick = (evt) => {
|
|
31248
|
+
this.groupByTrack = evt.target.checked;
|
|
31249
|
+
this.resetControlPanel();
|
|
31250
|
+
this.render();
|
|
31251
|
+
};
|
|
31252
|
+
|
|
31253
|
+
const groupByLabel = document.createElement('label');
|
|
31254
|
+
groupByLabel.for = 'groupByCB';
|
|
31255
|
+
groupByLabel.innerText = 'Group by track';
|
|
31256
|
+
groupByLabel.style.color = 'black';
|
|
31257
|
+
groupByLabel.style.paddingLeft = '10px';
|
|
30702
31258
|
const trackPanelRow = document.createElement('div');
|
|
30703
|
-
|
|
31259
|
+
trackPanelRow.style.width = '100%';
|
|
31260
|
+
trackPanelRow.style.paddingTop = '5px';
|
|
31261
|
+
trackPanelRow.style.paddingBottom = '5px';
|
|
31262
|
+
trackPanelRow.style.background = 'rgb(216, 230, 234)';
|
|
31263
|
+
trackPanelRow.appendChild(groupByCB);
|
|
31264
|
+
trackPanelRow.appendChild(groupByLabel);
|
|
31265
|
+
return trackPanelRow
|
|
31266
|
+
}
|
|
30704
31267
|
|
|
31268
|
+
addToControlPanel(chordSet) {
|
|
31269
|
+
|
|
31270
|
+
// single track row - container for hide-button | color-picker-swatch | track-name
|
|
31271
|
+
const row = document.createElement('div');
|
|
31272
|
+
this.controlPanel.appendChild(row);
|
|
30705
31273
|
|
|
30706
|
-
let element;
|
|
30707
31274
|
|
|
30708
31275
|
// track hide|show
|
|
30709
|
-
|
|
30710
|
-
|
|
30711
|
-
|
|
30712
|
-
|
|
30713
|
-
|
|
30714
|
-
if (true ===
|
|
30715
|
-
this.hideTrack(
|
|
31276
|
+
const hideShowButton = document.createElement('div');
|
|
31277
|
+
hideShowButton.className = 'igv-circview-button';
|
|
31278
|
+
row.appendChild(hideShowButton);
|
|
31279
|
+
hideShowButton.innerText = true === chordSet.visible ? 'Hide' : 'Show';
|
|
31280
|
+
hideShowButton.addEventListener('click', event => {
|
|
31281
|
+
if (true === chordSet.visible) {
|
|
31282
|
+
this.hideTrack(chordSet.name);
|
|
30716
31283
|
event.target.innerText = "Show";
|
|
30717
31284
|
} else {
|
|
30718
|
-
this.showTrack(
|
|
31285
|
+
this.showTrack(chordSet.name);
|
|
30719
31286
|
event.target.innerText = "Hide";
|
|
30720
31287
|
}
|
|
30721
|
-
|
|
30722
31288
|
});
|
|
30723
31289
|
|
|
30724
|
-
//
|
|
30725
|
-
|
|
30726
|
-
const
|
|
30727
|
-
|
|
30728
|
-
|
|
30729
|
-
|
|
30730
|
-
|
|
31290
|
+
// The alpha range slider. Create this here so we can reference it from the color picker
|
|
31291
|
+
const alphaSlider = document.createElement('input');
|
|
31292
|
+
const valueToAlpha = (value) => Math.exp(value / 200) / EXP5;
|
|
31293
|
+
const alphaToValue = (alpha) => 200 * Math.log(alpha * EXP5);
|
|
31294
|
+
|
|
31295
|
+
// color
|
|
31296
|
+
const colorPickerButton = document.createElement('div');
|
|
31297
|
+
colorPickerButton.className = 'igv-circview-button';
|
|
31298
|
+
colorPickerButton.innerHTML = ' '; // <- important for button to size properly
|
|
31299
|
+
row.appendChild(colorPickerButton);
|
|
31300
|
+
colorPickerButton.style.backgroundColor = setAlpha(chordSet.color, 1);
|
|
30731
31301
|
const pickerConfig =
|
|
30732
31302
|
{
|
|
30733
|
-
parent:
|
|
31303
|
+
parent: colorPickerButton,
|
|
30734
31304
|
popup: 'right',
|
|
30735
31305
|
editorFormat: 'rgb',
|
|
30736
|
-
color:
|
|
31306
|
+
color: chordSet.color,
|
|
30737
31307
|
onChange: ({rgbaString}) => {
|
|
30738
|
-
|
|
30739
|
-
this.setTrackColor(
|
|
31308
|
+
colorPickerButton.style.backgroundColor = setAlpha(rgbaString, 1);
|
|
31309
|
+
this.setTrackColor(chordSet.name, rgbaString);
|
|
31310
|
+
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
30740
31311
|
}
|
|
30741
31312
|
};
|
|
30742
|
-
|
|
30743
|
-
|
|
31313
|
+
const picker = new Picker(pickerConfig);
|
|
31314
|
+
|
|
31315
|
+
// alpha transparency
|
|
31316
|
+
alphaSlider.setAttribute('title', 'Adjust transparency of arcs');
|
|
31317
|
+
alphaSlider.type = 'range';
|
|
31318
|
+
//alphaSlider.className = 'igv-circview-alpha-slider'
|
|
31319
|
+
alphaSlider.style.width = '100px';
|
|
31320
|
+
alphaSlider.style.marginRight = '10px';
|
|
31321
|
+
alphaSlider.setAttribute('class', 'range');
|
|
31322
|
+
alphaSlider.setAttribute('min', '0');
|
|
31323
|
+
alphaSlider.setAttribute('max', '1000');
|
|
31324
|
+
alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
|
|
31325
|
+
alphaSlider.oninput = () => {
|
|
31326
|
+
const v = valueToAlpha(alphaSlider.value);
|
|
31327
|
+
this.setTrackColor(chordSet.name, setAlpha(chordSet.color, v));
|
|
31328
|
+
picker.setColor(chordSet.color);
|
|
31329
|
+
};
|
|
31330
|
+
row.appendChild(alphaSlider);
|
|
30744
31331
|
|
|
30745
31332
|
// track name
|
|
30746
|
-
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
|
|
31333
|
+
const trackNameDive = document.createElement('div');
|
|
31334
|
+
trackNameDive.style.color = 'black';
|
|
31335
|
+
row.appendChild(trackNameDive);
|
|
31336
|
+
trackNameDive.innerText = trackNameDive.title = chordSet.name;
|
|
30750
31337
|
|
|
30751
31338
|
}
|
|
30752
31339
|
|
|
@@ -30760,7 +31347,7 @@ class CircularView {
|
|
|
30760
31347
|
if (this.genomeId === igvGenome.id) {
|
|
30761
31348
|
return
|
|
30762
31349
|
}
|
|
30763
|
-
this.
|
|
31350
|
+
this.chordManager.clearChords();
|
|
30764
31351
|
this.genomeId = igvGenome.id;
|
|
30765
31352
|
this.chrNames = new Set(igvGenome.chromosomes.map(chr => shortChrName$1(chr.name)));
|
|
30766
31353
|
|
|
@@ -30823,39 +31410,24 @@ class CircularView {
|
|
|
30823
31410
|
|
|
30824
31411
|
addChords(newChords, options = {}) {
|
|
30825
31412
|
|
|
30826
|
-
const
|
|
31413
|
+
const tmp = options.track || options.name || "*";
|
|
31414
|
+
const trackName = tmp.split(' ')[0].replaceAll("%20", " ");
|
|
31415
|
+
const chordSetName = tmp.replaceAll("%20", " ");
|
|
31416
|
+
|
|
31417
|
+
const chordSet = {
|
|
31418
|
+
name: chordSetName,
|
|
31419
|
+
trackName: trackName,
|
|
31420
|
+
chords: newChords,
|
|
31421
|
+
color: options.color || "black",
|
|
31422
|
+
trackColor: options.trackColor || options.color || "black",
|
|
31423
|
+
visible: true,
|
|
31424
|
+
id: options.id || guid()
|
|
31425
|
+
};
|
|
30827
31426
|
|
|
30828
|
-
|
|
31427
|
+
this.chordManager.addChordSet(chordSet);
|
|
30829
31428
|
|
|
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
|
-
}
|
|
31429
|
+
this.resetControlPanel();
|
|
30848
31430
|
|
|
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
31431
|
this.render();
|
|
30860
31432
|
}
|
|
30861
31433
|
|
|
@@ -30881,8 +31453,9 @@ class CircularView {
|
|
|
30881
31453
|
}
|
|
30882
31454
|
|
|
30883
31455
|
clearChords() {
|
|
30884
|
-
this.tracks = []
|
|
30885
|
-
this.
|
|
31456
|
+
//this.tracks = []
|
|
31457
|
+
this.chordManager.clearChords();
|
|
31458
|
+
this.resetControlPanel();
|
|
30886
31459
|
this.render();
|
|
30887
31460
|
}
|
|
30888
31461
|
|
|
@@ -30927,8 +31500,8 @@ class CircularView {
|
|
|
30927
31500
|
this.parent.style.display = isVisible ? 'block' : 'none';
|
|
30928
31501
|
}
|
|
30929
31502
|
|
|
30930
|
-
hideTrack(
|
|
30931
|
-
let track = this.
|
|
31503
|
+
hideTrack(trackName) {
|
|
31504
|
+
let track = this.getTrack(trackName);
|
|
30932
31505
|
if (track) {
|
|
30933
31506
|
track.visible = false;
|
|
30934
31507
|
this.render();
|
|
@@ -30937,34 +31510,44 @@ class CircularView {
|
|
|
30937
31510
|
}
|
|
30938
31511
|
}
|
|
30939
31512
|
|
|
30940
|
-
showTrack(
|
|
30941
|
-
let
|
|
30942
|
-
if (
|
|
30943
|
-
const track = this.tracks[idx];
|
|
31513
|
+
showTrack(trackName) {
|
|
31514
|
+
let track = this.getTrack(trackName);
|
|
31515
|
+
if (track) {
|
|
30944
31516
|
track.visible = true;
|
|
30945
|
-
this.tracks.splice(idx, 1); // Change z-order
|
|
30946
|
-
this.tracks.push(track);
|
|
30947
31517
|
this.render();
|
|
30948
31518
|
} else {
|
|
30949
|
-
console.warn(`No track with name: ${
|
|
31519
|
+
console.warn(`No track with name: ${trackName}`);
|
|
30950
31520
|
}
|
|
30951
31521
|
}
|
|
30952
31522
|
|
|
31523
|
+
// showTrack(trackID) {
|
|
31524
|
+
// let idx = this.tracks.findIndex(t => trackID === t.id)
|
|
31525
|
+
// if (idx >= 0) {
|
|
31526
|
+
// const track = this.tracks[idx]
|
|
31527
|
+
// track.visible = true
|
|
31528
|
+
// this.tracks.splice(idx, 1) // Change z-order
|
|
31529
|
+
// this.tracks.push(track)
|
|
31530
|
+
// this.render()
|
|
31531
|
+
// } else {
|
|
31532
|
+
// console.warn(`No track with name: ${name}`)
|
|
31533
|
+
// }
|
|
31534
|
+
// }
|
|
31535
|
+
|
|
30953
31536
|
// TODO -- remove corresponding row from track panel
|
|
30954
31537
|
deleteTrack(trackID) {
|
|
30955
|
-
let idx = this.tracks.findIndex(t => trackID === t.
|
|
31538
|
+
let idx = this.tracks.findIndex(t => trackID === t.name);
|
|
30956
31539
|
if (idx >= 0) {
|
|
30957
31540
|
this.tracks.splice(idx, 1);
|
|
30958
31541
|
}
|
|
30959
31542
|
this.render();
|
|
30960
31543
|
}
|
|
30961
31544
|
|
|
30962
|
-
getTrack(
|
|
30963
|
-
return this.
|
|
31545
|
+
getTrack(name) {
|
|
31546
|
+
return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.getChordset(name)
|
|
30964
31547
|
}
|
|
30965
31548
|
|
|
30966
|
-
setTrackColor(
|
|
30967
|
-
const t = this.getTrack(
|
|
31549
|
+
setTrackColor(name, color) {
|
|
31550
|
+
const t = this.getTrack(name);
|
|
30968
31551
|
if (t) {
|
|
30969
31552
|
t.color = color;
|
|
30970
31553
|
const trackID = t.id;
|
|
@@ -30991,24 +31574,27 @@ class CircularView {
|
|
|
30991
31574
|
// Remove all children from possible previous renders. React might do this for us when we render, but just in case.
|
|
30992
31575
|
ReactDOM.unmountComponentAtNode(this.container);
|
|
30993
31576
|
|
|
30994
|
-
|
|
31577
|
+
|
|
31578
|
+
|
|
31579
|
+
const visibleChordSets =
|
|
31580
|
+
(this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets).filter(t => t.visible);
|
|
30995
31581
|
|
|
30996
31582
|
const jbrowseTracks = [];
|
|
30997
31583
|
const colors = [];
|
|
30998
31584
|
|
|
30999
|
-
for (let
|
|
31585
|
+
for (let chordSet of visibleChordSets) {
|
|
31586
|
+
|
|
31000
31587
|
jbrowseTracks.push({
|
|
31001
|
-
trackId:
|
|
31002
|
-
name:
|
|
31588
|
+
trackId: chordSet.id,
|
|
31589
|
+
name: chordSet.name,
|
|
31003
31590
|
assemblyNames: ['forIGV'],
|
|
31004
31591
|
type: 'VariantTrack',
|
|
31005
31592
|
adapter: {
|
|
31006
31593
|
type: 'FromConfigAdapter',
|
|
31007
|
-
features:
|
|
31594
|
+
features: chordSet.chords,
|
|
31008
31595
|
}
|
|
31009
31596
|
});
|
|
31010
|
-
colors.push(
|
|
31011
|
-
|
|
31597
|
+
colors.push(chordSet.color);
|
|
31012
31598
|
}
|
|
31013
31599
|
|
|
31014
31600
|
this.viewState = createViewState({
|
|
@@ -31017,7 +31603,7 @@ class CircularView {
|
|
|
31017
31603
|
});
|
|
31018
31604
|
|
|
31019
31605
|
// Set view colors
|
|
31020
|
-
for (let i = 0; i <
|
|
31606
|
+
for (let i = 0; i < visibleChordSets.length; i++) {
|
|
31021
31607
|
this.viewState.config.tracks[i].displays[0].renderer.strokeColor.set(colors[i]);
|
|
31022
31608
|
//this.viewState.config.tracks[i].displays[0].renderer.strokeColor.set("jexl:get(feature, 'color') || 'black'");
|
|
31023
31609
|
//this.viewState.config.tracks[i].displays[0].renderer.strokeColorSelected.set("jexl:get(feature, 'highlightColor') || 'red'");
|
|
@@ -31028,10 +31614,11 @@ class CircularView {
|
|
|
31028
31614
|
|
|
31029
31615
|
ReactDOM.render(this.element, this.container);
|
|
31030
31616
|
|
|
31031
|
-
|
|
31617
|
+
const onChordClick = this.config.onChordClick || defaultOnChordClick;
|
|
31618
|
+
for (let i = 0; i < visibleChordSets.length; i++) {
|
|
31032
31619
|
this.viewState.session.view.showTrack(this.viewState.config.tracks[i].trackId);
|
|
31033
|
-
if (
|
|
31034
|
-
this.viewState.pluginManager.jexl.addFunction('onChordClick',
|
|
31620
|
+
if (onChordClick) {
|
|
31621
|
+
this.viewState.pluginManager.jexl.addFunction('onChordClick', onChordClick);
|
|
31035
31622
|
this.viewState.config.tracks[i].displays[0].onChordClick.set(
|
|
31036
31623
|
'jexl:onChordClick(feature, track, pluginManager)'
|
|
31037
31624
|
);
|
|
@@ -31042,20 +31629,32 @@ class CircularView {
|
|
|
31042
31629
|
|
|
31043
31630
|
function setAlpha(rgba, alpha) {
|
|
31044
31631
|
const [a, b, c, ignore] = rgba.split(','); // rgba(r g b alpha)
|
|
31045
|
-
return `${
|
|
31632
|
+
return `${a},${b},${c},${alpha})`
|
|
31633
|
+
}
|
|
31634
|
+
|
|
31635
|
+
function getAlpha(rgba) {
|
|
31636
|
+
if (rgba.startsWith("rgba(")) {
|
|
31637
|
+
return Number(rgba.split(',')[3].replace(')', ''))
|
|
31638
|
+
} else {
|
|
31639
|
+
return 1
|
|
31640
|
+
}
|
|
31046
31641
|
}
|
|
31047
31642
|
|
|
31048
31643
|
function shortChrName$1(chrName) {
|
|
31049
31644
|
return chrName.startsWith("chr") ? chrName.substring(3) : chrName
|
|
31050
31645
|
}
|
|
31051
31646
|
|
|
31647
|
+
function defaultOnChordClick(feature, chordTrack, pluginManager) {
|
|
31648
|
+
console.log(feature);
|
|
31649
|
+
}
|
|
31650
|
+
|
|
31052
31651
|
function guid() {
|
|
31053
31652
|
return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
|
|
31054
31653
|
}
|
|
31055
31654
|
|
|
31056
31655
|
function embedCSS$1() {
|
|
31057
31656
|
|
|
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
|
|
31657
|
+
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
31658
|
|
|
31060
31659
|
const style = document.createElement('style');
|
|
31061
31660
|
style.setAttribute('type', 'text/css');
|
|
@@ -32417,59 +33016,61 @@ class AlignmentTrack {
|
|
|
32417
33016
|
list.push('<hr/>');
|
|
32418
33017
|
|
|
32419
33018
|
const clickedObject = this.getClickedObject(clickState);
|
|
33019
|
+
|
|
32420
33020
|
if (clickedObject) {
|
|
32421
33021
|
|
|
32422
33022
|
const showSoftClips = this.parent.showSoftClips;
|
|
32423
33023
|
const clickedAlignment = (typeof clickedObject.alignmentContaining === 'function') ?
|
|
32424
33024
|
clickedObject.alignmentContaining(clickState.genomicLocation, showSoftClips) :
|
|
32425
33025
|
clickedObject;
|
|
32426
|
-
|
|
32427
|
-
|
|
32428
|
-
|
|
32429
|
-
|
|
32430
|
-
|
|
32431
|
-
|
|
32432
|
-
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
|
|
33026
|
+
if (clickedAlignment) {
|
|
33027
|
+
if (clickedAlignment.isPaired() && clickedAlignment.isMateMapped()) {
|
|
33028
|
+
list.push({
|
|
33029
|
+
label: 'View mate in split screen',
|
|
33030
|
+
click: () => {
|
|
33031
|
+
if (clickedAlignment.mate) {
|
|
33032
|
+
const referenceFrame = clickState.viewport.referenceFrame;
|
|
33033
|
+
if (this.browser.genome.getChromosome(clickedAlignment.mate.chr)) {
|
|
33034
|
+
this.highlightedAlignmentReadNamed = clickedAlignment.readName;
|
|
33035
|
+
this.browser.presentMultiLocusPanel(clickedAlignment, referenceFrame);
|
|
33036
|
+
} else {
|
|
33037
|
+
Alert.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
|
|
33038
|
+
}
|
|
32438
33039
|
}
|
|
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
|
-
}
|
|
33040
|
+
},
|
|
33041
|
+
init: undefined
|
|
33042
|
+
});
|
|
32457
33043
|
}
|
|
32458
|
-
});
|
|
32459
33044
|
|
|
32460
|
-
if (isSecureContext()) {
|
|
32461
33045
|
list.push({
|
|
32462
|
-
label: '
|
|
33046
|
+
label: 'View read sequence',
|
|
32463
33047
|
click: () => {
|
|
32464
33048
|
const alignment = clickedAlignment;
|
|
32465
33049
|
if (!alignment) return
|
|
33050
|
+
|
|
32466
33051
|
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
32467
|
-
|
|
33052
|
+
if (!seqstring || "*" === seqstring) {
|
|
33053
|
+
Alert.presentAlert("Read sequence: *");
|
|
33054
|
+
} else {
|
|
33055
|
+
Alert.presentAlert(seqstring);
|
|
33056
|
+
}
|
|
32468
33057
|
}
|
|
32469
33058
|
});
|
|
32470
|
-
}
|
|
32471
33059
|
|
|
32472
|
-
|
|
33060
|
+
if (isSecureContext()) {
|
|
33061
|
+
list.push({
|
|
33062
|
+
label: 'Copy read sequence',
|
|
33063
|
+
click: () => {
|
|
33064
|
+
const alignment = clickedAlignment;
|
|
33065
|
+
if (!alignment) return
|
|
33066
|
+
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
33067
|
+
navigator.clipboard.writeText(seqstring);
|
|
33068
|
+
}
|
|
33069
|
+
});
|
|
33070
|
+
}
|
|
33071
|
+
|
|
33072
|
+
list.push('<hr/>');
|
|
33073
|
+
}
|
|
32473
33074
|
}
|
|
32474
33075
|
|
|
32475
33076
|
// Experimental JBrowse feature
|
|
@@ -32739,7 +33340,7 @@ function getChrColor(chr) {
|
|
|
32739
33340
|
chrColorMap[chr] = color;
|
|
32740
33341
|
return color
|
|
32741
33342
|
} else {
|
|
32742
|
-
const color = IGVColor.randomRGB();
|
|
33343
|
+
const color = IGVColor.randomRGB(0, 255);
|
|
32743
33344
|
chrColorMap[chr] = color;
|
|
32744
33345
|
return color
|
|
32745
33346
|
}
|
|
@@ -32747,7 +33348,7 @@ function getChrColor(chr) {
|
|
|
32747
33348
|
|
|
32748
33349
|
const chrColorMap = {
|
|
32749
33350
|
"chrX": "rgb(204, 153, 0)",
|
|
32750
|
-
"chrY": "rgb(153, 204, 0",
|
|
33351
|
+
"chrY": "rgb(153, 204, 0)",
|
|
32751
33352
|
"chrUn": "rgb(50, 50, 50)",
|
|
32752
33353
|
"chr1": "rgb(80, 80, 255)",
|
|
32753
33354
|
"chrI": "rgb(139, 155, 187)",
|
|
@@ -33001,143 +33602,68 @@ class RulerViewport extends TrackViewport {
|
|
|
33001
33602
|
|
|
33002
33603
|
}
|
|
33003
33604
|
|
|
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
|
-
}
|
|
33605
|
+
const viewportColumnManager =
|
|
33606
|
+
{
|
|
33607
|
+
createColumns: (columnContainer, count) => {
|
|
33076
33608
|
|
|
33077
|
-
|
|
33078
|
-
|
|
33609
|
+
for (let i = 0; i < count; i++) {
|
|
33610
|
+
if (0 === i) {
|
|
33611
|
+
createColumn(columnContainer, 'igv-column');
|
|
33612
|
+
} else {
|
|
33613
|
+
columnContainer.appendChild(div$1({class: 'igv-column-shim'}));
|
|
33614
|
+
createColumn(columnContainer, 'igv-column');
|
|
33615
|
+
}
|
|
33079
33616
|
}
|
|
33080
33617
|
|
|
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
|
-
}
|
|
33618
|
+
},
|
|
33091
33619
|
|
|
33092
|
-
|
|
33620
|
+
removeColumnAtIndex: (i, column) => {
|
|
33621
|
+
const shim = 0 === i ? column.nextElementSibling : column.previousElementSibling;
|
|
33622
|
+
column.remove();
|
|
33623
|
+
shim.remove();
|
|
33624
|
+
},
|
|
33093
33625
|
|
|
33094
|
-
|
|
33095
|
-
viewport.removeEventListener('click', this.boundClickHandler);
|
|
33096
|
-
}
|
|
33626
|
+
insertAfter: referenceElement => {
|
|
33097
33627
|
|
|
33098
|
-
|
|
33099
|
-
|
|
33100
|
-
}
|
|
33628
|
+
const shim = div$1({class: 'igv-column-shim'});
|
|
33629
|
+
insertElementAfter(shim, referenceElement);
|
|
33101
33630
|
|
|
33102
|
-
|
|
33631
|
+
const column = div$1({class: 'igv-column'});
|
|
33632
|
+
insertElementAfter(column, shim);
|
|
33103
33633
|
|
|
33104
|
-
|
|
33634
|
+
return column
|
|
33635
|
+
},
|
|
33105
33636
|
|
|
33106
|
-
|
|
33107
|
-
context,
|
|
33108
|
-
referenceFrame: this.referenceFrame,
|
|
33109
|
-
pixelWidth: width,
|
|
33110
|
-
pixelHeight: height
|
|
33111
|
-
});
|
|
33637
|
+
insertBefore: (referenceElement, count) => {
|
|
33112
33638
|
|
|
33113
|
-
|
|
33114
|
-
}
|
|
33639
|
+
for (let i = 0; i < count; i++) {
|
|
33115
33640
|
|
|
33116
|
-
|
|
33117
|
-
|
|
33118
|
-
}
|
|
33641
|
+
const column = div$1({class: 'igv-column'});
|
|
33642
|
+
insertElementBefore(column, referenceElement);
|
|
33119
33643
|
|
|
33120
|
-
|
|
33644
|
+
if (count > 1 && i > 0) {
|
|
33645
|
+
const columnShim = div$1({class: 'igv-column-shim'});
|
|
33646
|
+
insertElementBefore(columnShim, column);
|
|
33647
|
+
}
|
|
33121
33648
|
|
|
33122
|
-
|
|
33649
|
+
}
|
|
33123
33650
|
|
|
33124
|
-
|
|
33651
|
+
},
|
|
33125
33652
|
|
|
33126
|
-
|
|
33127
|
-
context: this.ideogram_ctx,
|
|
33128
|
-
referenceFrame,
|
|
33129
|
-
pixelWidth: this.$viewport.width(),
|
|
33130
|
-
pixelHeight: this.$viewport.height()
|
|
33131
|
-
});
|
|
33132
|
-
}
|
|
33653
|
+
indexOfColumn: (columnContainer, column) => {
|
|
33133
33654
|
|
|
33134
|
-
|
|
33135
|
-
}
|
|
33655
|
+
const allColumns = columnContainer.querySelectorAll('.igv-column');
|
|
33136
33656
|
|
|
33137
|
-
|
|
33138
|
-
|
|
33657
|
+
for (let i = 0; i < allColumns.length; i++) {
|
|
33658
|
+
const c = allColumns[ i ];
|
|
33659
|
+
if (c === column) {
|
|
33660
|
+
return i
|
|
33661
|
+
}
|
|
33662
|
+
}
|
|
33139
33663
|
|
|
33140
|
-
|
|
33664
|
+
return undefined
|
|
33665
|
+
},
|
|
33666
|
+
};
|
|
33141
33667
|
|
|
33142
33668
|
/*
|
|
33143
33669
|
* The MIT License (MIT)
|
|
@@ -33164,185 +33690,157 @@ class IdeogramViewport extends TrackViewport {
|
|
|
33164
33690
|
* THE SOFTWARE.
|
|
33165
33691
|
*/
|
|
33166
33692
|
|
|
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
|
-
*/
|
|
33693
|
+
class IdeogramViewport extends TrackViewport {
|
|
33173
33694
|
|
|
33174
|
-
|
|
33175
|
-
|
|
33176
|
-
|
|
33177
|
-
return (value !== undefined && (simpleTypes.has(valueType) || value.substring || value.toFixed))
|
|
33178
|
-
}
|
|
33695
|
+
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
33696
|
+
super(trackView, viewportColumn, referenceFrame, width);
|
|
33697
|
+
}
|
|
33179
33698
|
|
|
33180
|
-
|
|
33699
|
+
initializationHelper() {
|
|
33181
33700
|
|
|
33182
|
-
|
|
33183
|
-
|
|
33184
|
-
headers: config.headers,
|
|
33185
|
-
withCredentials: config.withCredentials,
|
|
33186
|
-
filename: config.filename
|
|
33187
|
-
};
|
|
33701
|
+
this.$ideogramCanvas = $$1('<canvas>', {class: 'igv-ideogram-canvas'});
|
|
33702
|
+
this.$ideogramCanvas.insertBefore(this.$canvas);
|
|
33188
33703
|
|
|
33189
|
-
|
|
33190
|
-
|
|
33704
|
+
const canvas = this.$ideogramCanvas.get(0);
|
|
33705
|
+
this.ideogram_ctx = canvas.getContext('2d');
|
|
33191
33706
|
|
|
33192
|
-
|
|
33193
|
-
|
|
33194
|
-
|
|
33195
|
-
* @returns {boolean}
|
|
33196
|
-
*/
|
|
33707
|
+
this.$canvas.remove();
|
|
33708
|
+
this.canvas = undefined;
|
|
33709
|
+
this.ctx = undefined;
|
|
33197
33710
|
|
|
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
|
-
// }
|
|
33711
|
+
this.addMouseHandlers();
|
|
33205
33712
|
|
|
33206
|
-
|
|
33207
|
-
var min, max;
|
|
33713
|
+
}
|
|
33208
33714
|
|
|
33209
|
-
|
|
33210
|
-
|
|
33211
|
-
|
|
33715
|
+
addMouseHandlers() {
|
|
33716
|
+
this.addBrowserObserver();
|
|
33717
|
+
this.addViewportClickHandler(this.$viewport.get(0));
|
|
33718
|
+
}
|
|
33212
33719
|
|
|
33213
|
-
|
|
33214
|
-
|
|
33215
|
-
|
|
33216
|
-
|
|
33720
|
+
removeMouseHandlers() {
|
|
33721
|
+
this.removeBrowserObserver();
|
|
33722
|
+
this.removeViewportClickHandler(this.$viewport.get(0));
|
|
33723
|
+
|
|
33724
|
+
}
|
|
33725
|
+
|
|
33726
|
+
addBrowserObserver() {
|
|
33727
|
+
|
|
33728
|
+
function observerHandler(referenceFrameList) {
|
|
33729
|
+
const column = this.$viewport.get(0).parentElement;
|
|
33730
|
+
if (null !== column) {
|
|
33731
|
+
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column);
|
|
33732
|
+
// console.log(`ideogram-viewport - locus-change-handler index(${ index }) ${ referenceFrameList[ index ].getLocusString() } ${ Date.now() } `)
|
|
33733
|
+
this.update(this.ideogram_ctx, this.$viewport.width(), this.$viewport.height(), referenceFrameList[ index ]);
|
|
33217
33734
|
}
|
|
33218
|
-
}
|
|
33735
|
+
}
|
|
33219
33736
|
|
|
33220
|
-
|
|
33221
|
-
|
|
33222
|
-
if (max < 0) max = 0;
|
|
33223
|
-
} else {
|
|
33224
|
-
// No features -- default
|
|
33225
|
-
min = 0;
|
|
33226
|
-
max = 100;
|
|
33737
|
+
this.boundObserverHandler = observerHandler.bind(this);
|
|
33738
|
+
this.browser.on('locuschange', this.boundObserverHandler);
|
|
33227
33739
|
}
|
|
33228
33740
|
|
|
33229
|
-
|
|
33230
|
-
|
|
33741
|
+
removeBrowserObserver() {
|
|
33742
|
+
this.browser.off('locuschange', this.boundObserverHandler);
|
|
33743
|
+
}
|
|
33231
33744
|
|
|
33232
|
-
|
|
33745
|
+
addViewportClickHandler(viewport) {
|
|
33233
33746
|
|
|
33234
|
-
|
|
33235
|
-
let ee = extent.end;
|
|
33747
|
+
function clickHandler(event) {
|
|
33236
33748
|
|
|
33237
|
-
|
|
33749
|
+
const column = viewport.parentElement;
|
|
33750
|
+
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column);
|
|
33751
|
+
const referenceFrame = this.browser.referenceFrameList[ index ];
|
|
33238
33752
|
|
|
33239
|
-
|
|
33240
|
-
|
|
33753
|
+
const {xNormalized, width} = translateMouseCoordinates$1(event, this.ideogram_ctx.canvas);
|
|
33754
|
+
const {bpLength} = this.browser.genome.getChromosome(referenceFrame.chr);
|
|
33755
|
+
const locusLength = referenceFrame.bpPerPixel * width;
|
|
33756
|
+
const chrCoveragePercentage = locusLength / bpLength;
|
|
33241
33757
|
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
|
|
33245
|
-
|
|
33246
|
-
ss = 0;
|
|
33247
|
-
ee = minimumBP;
|
|
33248
|
-
}
|
|
33758
|
+
let xPercentage = xNormalized;
|
|
33759
|
+
if (xPercentage - (chrCoveragePercentage / 2.0) < 0) {
|
|
33760
|
+
xPercentage = chrCoveragePercentage / 2.0;
|
|
33761
|
+
}
|
|
33249
33762
|
|
|
33250
|
-
|
|
33763
|
+
if (xPercentage + (chrCoveragePercentage / 2.0) > 1.0) {
|
|
33764
|
+
xPercentage = 1.0 - chrCoveragePercentage / 2.0;
|
|
33765
|
+
}
|
|
33251
33766
|
|
|
33252
|
-
|
|
33767
|
+
const ss = Math.round((xPercentage - (chrCoveragePercentage / 2.0)) * bpLength);
|
|
33768
|
+
const ee = Math.round((xPercentage + (chrCoveragePercentage / 2.0)) * bpLength);
|
|
33253
33769
|
|
|
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
|
-
}
|
|
33770
|
+
referenceFrame.start = ss;
|
|
33771
|
+
referenceFrame.end = ee;
|
|
33772
|
+
referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
33265
33773
|
|
|
33266
|
-
|
|
33267
|
-
extent.end = Math.floor(ee);
|
|
33268
|
-
};
|
|
33774
|
+
this.browser.updateViews(referenceFrame, this.browser.trackViews, true);
|
|
33269
33775
|
|
|
33270
|
-
|
|
33271
|
-
|
|
33272
|
-
|
|
33273
|
-
|
|
33274
|
-
* Released under the MIT License.
|
|
33275
|
-
*/
|
|
33776
|
+
}
|
|
33777
|
+
|
|
33778
|
+
this.boundClickHandler = clickHandler.bind(this);
|
|
33779
|
+
viewport.addEventListener('click', this.boundClickHandler);
|
|
33276
33780
|
|
|
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
33781
|
}
|
|
33284
|
-
return false
|
|
33285
|
-
};
|
|
33286
33782
|
|
|
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)
|
|
33783
|
+
removeViewportClickHandler(viewport) {
|
|
33784
|
+
viewport.removeEventListener('click', this.boundClickHandler);
|
|
33297
33785
|
}
|
|
33298
|
-
}
|
|
33299
33786
|
|
|
33300
|
-
|
|
33787
|
+
setWidth(width) {
|
|
33788
|
+
this.$viewport.width(width);
|
|
33789
|
+
}
|
|
33301
33790
|
|
|
33302
|
-
|
|
33303
|
-
units,
|
|
33304
|
-
value,
|
|
33305
|
-
floored;
|
|
33791
|
+
drawSVGWithContext(context, width, height, id, x, y, yClipOffset) {
|
|
33306
33792
|
|
|
33307
|
-
|
|
33308
|
-
denom = 1e6;
|
|
33309
|
-
units = " mb";
|
|
33310
|
-
} else if (raw > 1e4) {
|
|
33793
|
+
context.saveWithTranslationAndClipRect(id, x, y, width, height, yClipOffset);
|
|
33311
33794
|
|
|
33312
|
-
|
|
33313
|
-
|
|
33795
|
+
this.trackView.track.draw({
|
|
33796
|
+
context,
|
|
33797
|
+
referenceFrame: this.referenceFrame,
|
|
33798
|
+
pixelWidth: width,
|
|
33799
|
+
pixelHeight: height
|
|
33800
|
+
});
|
|
33314
33801
|
|
|
33315
|
-
|
|
33316
|
-
floored = Math.floor(value);
|
|
33317
|
-
return numberFormatter$1(floored) + units
|
|
33318
|
-
} else {
|
|
33319
|
-
return numberFormatter$1(raw) + " bp"
|
|
33802
|
+
context.restore();
|
|
33320
33803
|
}
|
|
33321
33804
|
|
|
33322
|
-
|
|
33323
|
-
|
|
33324
|
-
|
|
33325
|
-
|
|
33326
|
-
}
|
|
33805
|
+
update(context, pixelWidth, pixelHeight, referenceFrame) {
|
|
33806
|
+
this.$canvas.hide();
|
|
33807
|
+
IGVGraphics.configureHighDPICanvas(context, pixelWidth, pixelHeight);
|
|
33808
|
+
this.trackView.track.draw({ context, referenceFrame, pixelWidth, pixelHeight });
|
|
33809
|
+
}
|
|
33327
33810
|
|
|
33811
|
+
startSpinner() {
|
|
33812
|
+
}
|
|
33328
33813
|
|
|
33329
|
-
|
|
33330
|
-
|
|
33331
|
-
}
|
|
33814
|
+
stopSpinner() {
|
|
33815
|
+
}
|
|
33332
33816
|
|
|
33333
|
-
function createColumn(columnContainer, className) {
|
|
33334
|
-
const column = div$1({class: className});
|
|
33335
|
-
columnContainer.appendChild(column);
|
|
33336
33817
|
}
|
|
33337
33818
|
|
|
33819
|
+
/*
|
|
33820
|
+
* The MIT License (MIT)
|
|
33821
|
+
*
|
|
33822
|
+
* Copyright (c) 2014 Broad Institute
|
|
33823
|
+
*
|
|
33824
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33825
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
33826
|
+
* in the Software without restriction, including without limitation the rights
|
|
33827
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
33828
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
33829
|
+
* furnished to do so, subject to the following conditions:
|
|
33830
|
+
*
|
|
33831
|
+
* The above copyright notice and this permission notice shall be included in
|
|
33832
|
+
* all copies or substantial portions of the Software.
|
|
33833
|
+
*
|
|
33834
|
+
*
|
|
33835
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33836
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33837
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
33838
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33839
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33840
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
33841
|
+
* THE SOFTWARE.
|
|
33842
|
+
*/
|
|
33338
33843
|
|
|
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
33844
|
|
|
33347
33845
|
function createViewport(trackView, column, referenceFrame, width) {
|
|
33348
33846
|
|
|
@@ -33355,13 +33853,6 @@ function createViewport(trackView, column, referenceFrame, width) {
|
|
|
33355
33853
|
}
|
|
33356
33854
|
}
|
|
33357
33855
|
|
|
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
33856
|
const maxFontSize = 10;
|
|
33366
33857
|
|
|
33367
33858
|
const fontConfigureTemplate =
|
|
@@ -33377,7 +33868,7 @@ class SampleNameViewport {
|
|
|
33377
33868
|
|
|
33378
33869
|
constructor(trackView, column, unused, width) {
|
|
33379
33870
|
|
|
33380
|
-
this.guid = guid$
|
|
33871
|
+
this.guid = guid$2();
|
|
33381
33872
|
this.trackView = trackView;
|
|
33382
33873
|
|
|
33383
33874
|
this.browser = trackView.browser;
|
|
@@ -33495,7 +33986,7 @@ class SampleNameViewport {
|
|
|
33495
33986
|
const {width, height} = this.viewport.getBoundingClientRect();
|
|
33496
33987
|
|
|
33497
33988
|
const str = (this.trackView.track.name || this.trackView.track.id).replace(/\W/g, '');
|
|
33498
|
-
const id = `${str}_sample_names_guid_${guid$
|
|
33989
|
+
const id = `${str}_sample_names_guid_${guid$2()}`;
|
|
33499
33990
|
|
|
33500
33991
|
context.saveWithTranslationAndClipRect(id, deltaX, deltaY + yScrollDelta, width, height, -yScrollDelta);
|
|
33501
33992
|
|
|
@@ -33879,7 +34370,7 @@ class TrackView {
|
|
|
33879
34370
|
|
|
33880
34371
|
constructor(browser, columnContainer, track) {
|
|
33881
34372
|
|
|
33882
|
-
this.namespace = `trackview-${guid$
|
|
34373
|
+
this.namespace = `trackview-${guid$2()}`;
|
|
33883
34374
|
|
|
33884
34375
|
this.browser = browser;
|
|
33885
34376
|
this.track = track;
|
|
@@ -34234,11 +34725,13 @@ class TrackView {
|
|
|
34234
34725
|
for (let viewport of reloadableViewports) {
|
|
34235
34726
|
await viewport.loadFeatures();
|
|
34236
34727
|
}
|
|
34728
|
+
|
|
34729
|
+
if (this.disposed) return // Track was removed during load
|
|
34237
34730
|
|
|
34238
34731
|
// Very special case for variant tracks in multilocus view. The # of rows to allocate to the variant (site)
|
|
34239
34732
|
// section depends on data from all the views. We only need to adjust this however if any data was loaded
|
|
34240
34733
|
// (i.e. reloadableViewports.length > 0)
|
|
34241
|
-
if (typeof this.track.variantRowCount === 'function' && reloadableViewports.length > 0) {
|
|
34734
|
+
if (this.track && typeof this.track.variantRowCount === 'function' && reloadableViewports.length > 0) {
|
|
34242
34735
|
let maxRow = 0;
|
|
34243
34736
|
for (let viewport of this.viewports) {
|
|
34244
34737
|
if (viewport.tile && viewport.tile.features) {
|
|
@@ -34254,7 +34747,6 @@ class TrackView {
|
|
|
34254
34747
|
}
|
|
34255
34748
|
}
|
|
34256
34749
|
|
|
34257
|
-
if (this.disposed) return // Track was removed during load
|
|
34258
34750
|
|
|
34259
34751
|
if (this.track.autoscale) {
|
|
34260
34752
|
let allFeatures = [];
|
|
@@ -34702,7 +35194,7 @@ function renderSVGAxis(context, track, axisCanvas, deltaX, deltaY) {
|
|
|
34702
35194
|
const {y, width, height} = axisCanvas.getBoundingClientRect();
|
|
34703
35195
|
|
|
34704
35196
|
const str = (track.name || track.id).replace(/\W/g, '');
|
|
34705
|
-
const id = `${str}_axis_guid_${guid$
|
|
35197
|
+
const id = `${str}_axis_guid_${guid$2()}`;
|
|
34706
35198
|
|
|
34707
35199
|
context.saveWithTranslationAndClipRect(id, deltaX, y + deltaY, width, height, 0);
|
|
34708
35200
|
|
|
@@ -34982,6 +35474,9 @@ class GFFFeature {
|
|
|
34982
35474
|
|
|
34983
35475
|
pd.push({name: 'Type', value: this.type});
|
|
34984
35476
|
pd.push({name: 'Source', value: this.source});
|
|
35477
|
+
if (this.score !== undefined) {
|
|
35478
|
+
pd.push({name: 'Score', value: this.score});
|
|
35479
|
+
}
|
|
34985
35480
|
|
|
34986
35481
|
if (this.attributeString) {
|
|
34987
35482
|
const atts = parseAttributeString(this.attributeString, this.delim);
|
|
@@ -35230,7 +35725,7 @@ function decode(tokens, header) {
|
|
|
35230
35725
|
chr: tokens[0],
|
|
35231
35726
|
start: parseInt(tokens[3]) - 1,
|
|
35232
35727
|
end: parseInt(tokens[4]),
|
|
35233
|
-
score: "." === tokens[5] ?
|
|
35728
|
+
score: "." === tokens[5] ? undefined : Number(tokens[5]),
|
|
35234
35729
|
strand: tokens[6],
|
|
35235
35730
|
phase: "." === tokens[7] ? 0 : parseInt(tokens[7]),
|
|
35236
35731
|
attributeString: tokens[8],
|
|
@@ -36586,244 +37081,29 @@ class SegFeature {
|
|
|
36586
37081
|
* THE SOFTWARE.
|
|
36587
37082
|
*/
|
|
36588
37083
|
|
|
36589
|
-
|
|
36590
|
-
|
|
36591
|
-
|
|
37084
|
+
/**
|
|
37085
|
+
* Create a variant from an array of tokens representing a line in a "VCF" file
|
|
37086
|
+
* @param tokens
|
|
37087
|
+
*/
|
|
36592
37088
|
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 = {};
|
|
37089
|
+
const variant = new Variant();
|
|
37090
|
+
variant.chr = tokens[0]; // TODO -- use genome aliases
|
|
37091
|
+
variant.pos = parseInt(tokens[1]);
|
|
37092
|
+
variant.names = tokens[2]; // id in VCF
|
|
37093
|
+
variant.referenceBases = tokens[3];
|
|
37094
|
+
variant.alternateBases = tokens[4];
|
|
37095
|
+
variant.quality = tokens[5];
|
|
37096
|
+
variant.filter = tokens[6];
|
|
37097
|
+
variant.info = {};
|
|
37098
|
+
const infoStr = tokens[7];
|
|
36771
37099
|
if (infoStr) {
|
|
36772
|
-
infoStr.split(';')
|
|
37100
|
+
for (let elem of infoStr.split(';')) {
|
|
36773
37101
|
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
|
|
37102
|
+
variant.info[element[0]] = element[1];
|
|
36785
37103
|
}
|
|
36786
37104
|
}
|
|
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)
|
|
37105
|
+
variant.init();
|
|
37106
|
+
return variant;
|
|
36827
37107
|
}
|
|
36828
37108
|
|
|
36829
37109
|
|
|
@@ -36887,6 +37167,217 @@ function createGAVariant(json) {
|
|
|
36887
37167
|
|
|
36888
37168
|
}
|
|
36889
37169
|
|
|
37170
|
+
|
|
37171
|
+
class Variant {
|
|
37172
|
+
|
|
37173
|
+
init() {
|
|
37174
|
+
|
|
37175
|
+
const ref = this.referenceBases;
|
|
37176
|
+
const altBases = this.alternateBases;
|
|
37177
|
+
|
|
37178
|
+
if (this.info) {
|
|
37179
|
+
if (this.info["VT"]) {
|
|
37180
|
+
this.type = this.info["VT"];
|
|
37181
|
+
} else if (this.info["SVTYPE"]) {
|
|
37182
|
+
this.type = "SV";
|
|
37183
|
+
} else if (this.info["PERIOD"]) {
|
|
37184
|
+
this.type = "STR";
|
|
37185
|
+
}
|
|
37186
|
+
}
|
|
37187
|
+
if (this.type === undefined) {
|
|
37188
|
+
this.type = determineType(ref, altBases);
|
|
37189
|
+
}
|
|
37190
|
+
if (this.type === "NONVARIANT") {
|
|
37191
|
+
this.heterozygosity = 0;
|
|
37192
|
+
}
|
|
37193
|
+
|
|
37194
|
+
// Determine start/end coordinates -- these are the coordinates representing the actual variant,
|
|
37195
|
+
// not the leading or trailing reference
|
|
37196
|
+
if (this.info["END"]) {
|
|
37197
|
+
this.start = this.pos - 1;
|
|
37198
|
+
if (this.info["CHR2"] && this.info["CHR2"] !== this.chr) {
|
|
37199
|
+
this.end = this.start + 1;
|
|
37200
|
+
} else {
|
|
37201
|
+
this.end = Number.parseInt(this.info["END"]);
|
|
37202
|
+
}
|
|
37203
|
+
} else {
|
|
37204
|
+
if (this.type === "NONVARIANT") {
|
|
37205
|
+
this.start = this.pos - 1; // convert to 0-based coordinate convention
|
|
37206
|
+
this.end = this.start + ref.length;
|
|
37207
|
+
} else {
|
|
37208
|
+
|
|
37209
|
+
const altTokens = altBases.split(",").filter(token => token.length > 0);
|
|
37210
|
+
this.alleles = [];
|
|
37211
|
+
this.start = undefined;
|
|
37212
|
+
this.end = undefined;
|
|
37213
|
+
|
|
37214
|
+
for (let alt of altTokens) {
|
|
37215
|
+
|
|
37216
|
+
this.alleles.push(alt);
|
|
37217
|
+
|
|
37218
|
+
// We don't yet handle SV and other special alt representations
|
|
37219
|
+
if ("SV" !== this.type && isKnownAlt(alt)) {
|
|
37220
|
+
|
|
37221
|
+
let altLength = alt.length;
|
|
37222
|
+
let lengthOnRef = ref.length;
|
|
37223
|
+
const lmin = Math.min(altLength, lengthOnRef);
|
|
37224
|
+
|
|
37225
|
+
// Trim off matching bases. Try first match, then right -> left, then any remaining left -> right
|
|
37226
|
+
let s = 0;
|
|
37227
|
+
|
|
37228
|
+
while (s < lmin && (ref.charCodeAt(s) === alt.charCodeAt(s))) {
|
|
37229
|
+
s++;
|
|
37230
|
+
altLength--;
|
|
37231
|
+
lengthOnRef--;
|
|
37232
|
+
}
|
|
37233
|
+
|
|
37234
|
+
// right -> left from end
|
|
37235
|
+
while (altLength > 0 && lengthOnRef > 0) {
|
|
37236
|
+
const altIdx = s + altLength - 1;
|
|
37237
|
+
const refIdx = s + lengthOnRef - 1;
|
|
37238
|
+
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
37239
|
+
altLength--;
|
|
37240
|
+
lengthOnRef--;
|
|
37241
|
+
} else {
|
|
37242
|
+
break
|
|
37243
|
+
}
|
|
37244
|
+
}
|
|
37245
|
+
|
|
37246
|
+
// if any remaining, left -> right
|
|
37247
|
+
while (altLength > 0 && lengthOnRef > 0) {
|
|
37248
|
+
const altIdx = s;
|
|
37249
|
+
const refIdx = s;
|
|
37250
|
+
if (alt.charCodeAt(altIdx) === ref.charCodeAt(refIdx)) {
|
|
37251
|
+
s++;
|
|
37252
|
+
altLength--;
|
|
37253
|
+
lengthOnRef--;
|
|
37254
|
+
} else {
|
|
37255
|
+
break
|
|
37256
|
+
}
|
|
37257
|
+
}
|
|
37258
|
+
|
|
37259
|
+
const alleleStart = this.pos + s - 1; // -1 for zero based coordinates
|
|
37260
|
+
const alleleEnd = alleleStart + lengthOnRef;
|
|
37261
|
+
this.start = this.start === undefined ? alleleStart : Math.min(this.start, alleleStart);
|
|
37262
|
+
this.end = this.end === undefined ? alleleEnd : Math.max(this.end, alleleEnd);
|
|
37263
|
+
}
|
|
37264
|
+
}
|
|
37265
|
+
|
|
37266
|
+
// Default to single base representation @ position for variant types not otherwise handled
|
|
37267
|
+
if (this.start === undefined) {
|
|
37268
|
+
this.start = this.pos - 1;
|
|
37269
|
+
this.end = this.pos;
|
|
37270
|
+
}
|
|
37271
|
+
}
|
|
37272
|
+
}
|
|
37273
|
+
}
|
|
37274
|
+
|
|
37275
|
+
|
|
37276
|
+
popupData(genomicLocation, genomeId) {
|
|
37277
|
+
|
|
37278
|
+
|
|
37279
|
+
const posString = `${numberFormatter$1(this.pos)}`;
|
|
37280
|
+
const locString = this.start === this.end ?
|
|
37281
|
+
`${numberFormatter$1(this.start)} | ${numberFormatter$1(this.start + 1)}` :
|
|
37282
|
+
`${numberFormatter$1(this.start + 1)}-${numberFormatter$1(this.end)}`;
|
|
37283
|
+
const fields = [
|
|
37284
|
+
{name: "Chr", value: this.chr},
|
|
37285
|
+
{name: "Pos", value: posString},
|
|
37286
|
+
{name: "Loc", value: locString},
|
|
37287
|
+
{name: "Names", value: this.names ? this.names : ""},
|
|
37288
|
+
{name: "Ref", value: this.referenceBases},
|
|
37289
|
+
{name: "Alt", value: this.alternateBases.replace("<", "<")},
|
|
37290
|
+
{name: "Qual", value: this.quality},
|
|
37291
|
+
{name: "Filter", value: this.filter}
|
|
37292
|
+
];
|
|
37293
|
+
|
|
37294
|
+
if ("SNP" === this.type) {
|
|
37295
|
+
let ref = this.referenceBases;
|
|
37296
|
+
if (ref.length === 1) {
|
|
37297
|
+
let altArray = this.alternateBases.split(",");
|
|
37298
|
+
for (let alt of altArray) {
|
|
37299
|
+
if (alt.length === 1) {
|
|
37300
|
+
let l = TrackBase.getCravatLink(this.chr, this.pos, ref, alt, genomeId);
|
|
37301
|
+
if (l) {
|
|
37302
|
+
fields.push('<hr/>');
|
|
37303
|
+
fields.push({html: l});
|
|
37304
|
+
}
|
|
37305
|
+
}
|
|
37306
|
+
}
|
|
37307
|
+
}
|
|
37308
|
+
}
|
|
37309
|
+
|
|
37310
|
+
if (this.hasOwnProperty("heterozygosity")) {
|
|
37311
|
+
fields.push({name: "Heterozygosity", value: this.heterozygosity});
|
|
37312
|
+
}
|
|
37313
|
+
|
|
37314
|
+
if (this.info) {
|
|
37315
|
+
fields.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
|
|
37316
|
+
for (let key of Object.keys(this.info)) {
|
|
37317
|
+
fields.push({name: key, value: arrayToString(decodeURIComponent(this.info[key]))});
|
|
37318
|
+
}
|
|
37319
|
+
}
|
|
37320
|
+
|
|
37321
|
+
return fields
|
|
37322
|
+
|
|
37323
|
+
};
|
|
37324
|
+
|
|
37325
|
+
isRefBlock() {
|
|
37326
|
+
return "NONVARIANT" === this.type
|
|
37327
|
+
}
|
|
37328
|
+
|
|
37329
|
+
}
|
|
37330
|
+
|
|
37331
|
+
const knownAltBases = new Set(["A", "C", "T", "G"].map(c => c.charCodeAt(0)));
|
|
37332
|
+
|
|
37333
|
+
function isKnownAlt(alt) {
|
|
37334
|
+
for (let i = 0; i < alt.length; i++) {
|
|
37335
|
+
if (!knownAltBases.has(alt.charCodeAt(i))) {
|
|
37336
|
+
return false
|
|
37337
|
+
}
|
|
37338
|
+
}
|
|
37339
|
+
return true
|
|
37340
|
+
}
|
|
37341
|
+
|
|
37342
|
+
|
|
37343
|
+
function determineType(ref, altAlleles) {
|
|
37344
|
+
const refLength = ref.length;
|
|
37345
|
+
if (altAlleles === undefined) {
|
|
37346
|
+
return "UNKNOWN"
|
|
37347
|
+
} else if (altAlleles.trim().length === 0 ||
|
|
37348
|
+
altAlleles === "<NON_REF>" ||
|
|
37349
|
+
altAlleles === "<*>" ||
|
|
37350
|
+
altAlleles === ".") {
|
|
37351
|
+
return "NONVARIANT"
|
|
37352
|
+
} else {
|
|
37353
|
+
const alleles = altAlleles.split(",");
|
|
37354
|
+
const types = alleles.map(function (a) {
|
|
37355
|
+
if (refLength === 1 && a.length === 1) {
|
|
37356
|
+
return "SNP"
|
|
37357
|
+
} else {
|
|
37358
|
+
return "<NON_REF>" === a ? "NONVARIANT" : "OTHER"
|
|
37359
|
+
}
|
|
37360
|
+
});
|
|
37361
|
+
let type = types[0];
|
|
37362
|
+
for (let t of types) {
|
|
37363
|
+
if (t !== type) {
|
|
37364
|
+
return "MIXED"
|
|
37365
|
+
}
|
|
37366
|
+
}
|
|
37367
|
+
return type
|
|
37368
|
+
}
|
|
37369
|
+
}
|
|
37370
|
+
|
|
37371
|
+
function arrayToString(value, delim) {
|
|
37372
|
+
|
|
37373
|
+
if (delim === undefined) delim = ",";
|
|
37374
|
+
|
|
37375
|
+
if (!(Array.isArray(value))) {
|
|
37376
|
+
return value
|
|
37377
|
+
}
|
|
37378
|
+
return value.join(delim)
|
|
37379
|
+
}
|
|
37380
|
+
|
|
36890
37381
|
/*
|
|
36891
37382
|
* The MIT License (MIT)
|
|
36892
37383
|
*
|
|
@@ -37031,6 +37522,7 @@ class VcfParser {
|
|
|
37031
37522
|
if (tokens.length === nExpectedColumns) {
|
|
37032
37523
|
const variant = createVCFVariant(tokens);
|
|
37033
37524
|
variant.header = this.header; // Keep a pointer to the header to interpret fields for popup text
|
|
37525
|
+
//variant.line = line // Uncomment for debugging
|
|
37034
37526
|
allFeatures.push(variant);
|
|
37035
37527
|
|
|
37036
37528
|
if (tokens.length > 9) {
|
|
@@ -39153,6 +39645,7 @@ class HtsgetVariantReader extends HtsgetReader {
|
|
|
39153
39645
|
* THE SOFTWARE.
|
|
39154
39646
|
*/
|
|
39155
39647
|
|
|
39648
|
+
const DEFAULT_MAX_WG_COUNT = 10000;
|
|
39156
39649
|
|
|
39157
39650
|
/**
|
|
39158
39651
|
* feature source for "bed like" files (tab or whitespace delimited files with 1 feature per line: bed, gff, vcf, etc)
|
|
@@ -39167,6 +39660,7 @@ class TextFeatureSource {
|
|
|
39167
39660
|
this.config = config || {};
|
|
39168
39661
|
this.genome = genome;
|
|
39169
39662
|
this.sourceType = (config.sourceType === undefined ? "file" : config.sourceType);
|
|
39663
|
+
this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
|
|
39170
39664
|
|
|
39171
39665
|
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "tdf"]);
|
|
39172
39666
|
|
|
@@ -39384,10 +39878,22 @@ class TextFeatureSource {
|
|
|
39384
39878
|
// TODO -- filter by pixel size
|
|
39385
39879
|
getWGFeatures(allFeatures) {
|
|
39386
39880
|
|
|
39881
|
+
const makeWGFeature = (f) => {
|
|
39882
|
+
const wg = Object.assign({}, f);
|
|
39883
|
+
wg.chr = "all";
|
|
39884
|
+
wg.start = genome.getGenomeCoordinate(f.chr, f.start);
|
|
39885
|
+
wg.end = genome.getGenomeCoordinate(f.chr, f.end);
|
|
39886
|
+
wg._f = f;
|
|
39887
|
+
// Don't draw exons in whole genome view
|
|
39888
|
+
if (wg["exons"]) delete wg["exons"];
|
|
39889
|
+
return wg
|
|
39890
|
+
};
|
|
39891
|
+
|
|
39387
39892
|
const genome = this.genome;
|
|
39388
39893
|
const wgChromosomeNames = new Set(genome.wgChromosomeNames);
|
|
39389
39894
|
const wgFeatures = [];
|
|
39390
|
-
|
|
39895
|
+
let count = 0;
|
|
39896
|
+
const max = this.maxWGCount;
|
|
39391
39897
|
for (let c of genome.wgChromosomeNames) {
|
|
39392
39898
|
|
|
39393
39899
|
const features = allFeatures[c];
|
|
@@ -39396,19 +39902,18 @@ class TextFeatureSource {
|
|
|
39396
39902
|
for (let f of features) {
|
|
39397
39903
|
let queryChr = genome.getChromosomeName(f.chr);
|
|
39398
39904
|
if (wgChromosomeNames.has(queryChr)) {
|
|
39399
|
-
|
|
39400
|
-
|
|
39401
|
-
|
|
39402
|
-
|
|
39403
|
-
|
|
39404
|
-
|
|
39405
|
-
|
|
39406
|
-
|
|
39407
|
-
|
|
39408
|
-
|
|
39409
|
-
|
|
39410
|
-
wgFeatures.push(wg);
|
|
39905
|
+
if (wgFeatures.length < max) {
|
|
39906
|
+
wgFeatures.push(makeWGFeature(f));
|
|
39907
|
+
} else {
|
|
39908
|
+
//Reservoir sampling
|
|
39909
|
+
const samplingProb = max / (count + 1);
|
|
39910
|
+
if (Math.random() < samplingProb) {
|
|
39911
|
+
const idx = Math.floor(Math.random() * (max - 1));
|
|
39912
|
+
wgFeatures[idx] = makeWGFeature(f);
|
|
39913
|
+
}
|
|
39914
|
+
}
|
|
39411
39915
|
}
|
|
39916
|
+
count++;
|
|
39412
39917
|
}
|
|
39413
39918
|
}
|
|
39414
39919
|
}
|
|
@@ -42062,7 +42567,7 @@ class FeatureTrack extends TrackBase {
|
|
|
42062
42567
|
desc += "</html>";
|
|
42063
42568
|
return desc
|
|
42064
42569
|
} else {
|
|
42065
|
-
return
|
|
42570
|
+
return super.description();
|
|
42066
42571
|
}
|
|
42067
42572
|
|
|
42068
42573
|
};
|
|
@@ -42144,8 +42649,12 @@ class WigTrack extends TrackBase {
|
|
|
42144
42649
|
|
|
42145
42650
|
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
42146
42651
|
if ("bigwig" === format) {
|
|
42652
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
42653
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
42147
42654
|
this.featureSource = new BWSource(config, this.browser.genome);
|
|
42148
42655
|
} else if ("tdf" === format) {
|
|
42656
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
42657
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
42149
42658
|
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
42150
42659
|
} else {
|
|
42151
42660
|
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
@@ -42194,7 +42703,20 @@ class WigTrack extends TrackBase {
|
|
|
42194
42703
|
}
|
|
42195
42704
|
|
|
42196
42705
|
menuItemList() {
|
|
42197
|
-
|
|
42706
|
+
let items = [];
|
|
42707
|
+
if (this.flipAxis !== undefined) {
|
|
42708
|
+
items.push({
|
|
42709
|
+
label:"Flip y-axis",
|
|
42710
|
+
click: () => {
|
|
42711
|
+
this.flipAxis = !this.flipAxis;
|
|
42712
|
+
this.trackView.repaintViews();
|
|
42713
|
+
}
|
|
42714
|
+
});
|
|
42715
|
+
}
|
|
42716
|
+
|
|
42717
|
+
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
42718
|
+
|
|
42719
|
+
return items
|
|
42198
42720
|
}
|
|
42199
42721
|
|
|
42200
42722
|
async getHeader() {
|
|
@@ -42205,6 +42727,27 @@ class WigTrack extends TrackBase {
|
|
|
42205
42727
|
return this.header
|
|
42206
42728
|
}
|
|
42207
42729
|
|
|
42730
|
+
// TODO: refactor to igvUtils.js
|
|
42731
|
+
getScaleFactor(min, max, height, logScale) {
|
|
42732
|
+
const scale = logScale ? height / (Math.log10(max + 1) - (min <= 0 ? 0 : Math.log10(min + 1))) : height / (max - min);
|
|
42733
|
+
return scale
|
|
42734
|
+
}
|
|
42735
|
+
|
|
42736
|
+
computeYPixelValue(yValue, yScaleFactor) {
|
|
42737
|
+
return (this.flipAxis ? (yValue - this.dataRange.min) : (this.dataRange.max - yValue)) * yScaleFactor
|
|
42738
|
+
}
|
|
42739
|
+
|
|
42740
|
+
computeYPixelValueInLogScale(yValue, yScaleFactor) {
|
|
42741
|
+
let maxValue = this.dataRange.max;
|
|
42742
|
+
let minValue = this.dataRange.min;
|
|
42743
|
+
if (maxValue <= 0) return 0 // TODO:
|
|
42744
|
+
if (minValue <= -1) minValue = 0;
|
|
42745
|
+
minValue = (minValue <= 0) ? 0 : Math.log10(minValue + 1);
|
|
42746
|
+
maxValue = Math.log10(maxValue + 1);
|
|
42747
|
+
yValue = Math.log10(yValue + 1);
|
|
42748
|
+
return ((this.flipAxis ? (yValue - minValue) : (maxValue - yValue)) * yScaleFactor)
|
|
42749
|
+
}
|
|
42750
|
+
|
|
42208
42751
|
draw(options) {
|
|
42209
42752
|
|
|
42210
42753
|
const features = options.features;
|
|
@@ -42212,7 +42755,7 @@ class WigTrack extends TrackBase {
|
|
|
42212
42755
|
const bpPerPixel = options.bpPerPixel;
|
|
42213
42756
|
const bpStart = options.bpStart;
|
|
42214
42757
|
const pixelWidth = options.pixelWidth;
|
|
42215
|
-
|
|
42758
|
+
options.pixelHeight;
|
|
42216
42759
|
const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
|
|
42217
42760
|
let lastPixelEnd = -1;
|
|
42218
42761
|
let lastValue = -1;
|
|
@@ -42224,9 +42767,10 @@ class WigTrack extends TrackBase {
|
|
|
42224
42767
|
baselineColor = IGVColor.addAlpha(posColor, 0.1);
|
|
42225
42768
|
}
|
|
42226
42769
|
|
|
42227
|
-
const
|
|
42228
|
-
|
|
42229
|
-
|
|
42770
|
+
const scaleFactor = this.getScaleFactor(this.dataRange.min, this.dataRange.max, options.pixelHeight, this.logScale);
|
|
42771
|
+
const yScale = (yValue) => this.logScale
|
|
42772
|
+
? this.computeYPixelValueInLogScale(yValue, scaleFactor)
|
|
42773
|
+
: this.computeYPixelValue(yValue, scaleFactor);
|
|
42230
42774
|
|
|
42231
42775
|
if (features && features.length > 0) {
|
|
42232
42776
|
|
|
@@ -42236,7 +42780,7 @@ class WigTrack extends TrackBase {
|
|
|
42236
42780
|
// nothing to paint.
|
|
42237
42781
|
if (this.dataRange.max > this.dataRange.min) {
|
|
42238
42782
|
|
|
42239
|
-
const y0 =
|
|
42783
|
+
const y0 = yScale(0);
|
|
42240
42784
|
for (let f of features) {
|
|
42241
42785
|
|
|
42242
42786
|
if (f.end < bpStart) continue
|
|
@@ -42260,9 +42804,6 @@ class WigTrack extends TrackBase {
|
|
|
42260
42804
|
|
|
42261
42805
|
} else {
|
|
42262
42806
|
let height = y - y0;
|
|
42263
|
-
if ((Math.abs(height)) < 1) {
|
|
42264
|
-
height = height < 0 ? -1 : 1;
|
|
42265
|
-
}
|
|
42266
42807
|
const pixelEnd = x + width;
|
|
42267
42808
|
if (pixelEnd > lastPixelEnd || (f.value >= 0 && f.value > lastValue) || (f.value < 0 && f.value < lastNegValue)) {
|
|
42268
42809
|
IGVGraphics.fillRect(ctx, x, y0, width, height, {fillStyle: color});
|
|
@@ -42359,6 +42900,21 @@ class WigTrack extends TrackBase {
|
|
|
42359
42900
|
dispose() {
|
|
42360
42901
|
this.trackView = undefined;
|
|
42361
42902
|
}
|
|
42903
|
+
|
|
42904
|
+
/**
|
|
42905
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
42906
|
+
*
|
|
42907
|
+
* @returns {*|{}}
|
|
42908
|
+
*/
|
|
42909
|
+
getState() {
|
|
42910
|
+
|
|
42911
|
+
const config = super.getState();
|
|
42912
|
+
|
|
42913
|
+
if (this.flipAxis !== undefined) config.flipAxis = this.flipAxis;
|
|
42914
|
+
if (this.logScale !== undefined) config.logScale = this.logScale;
|
|
42915
|
+
|
|
42916
|
+
return config
|
|
42917
|
+
}
|
|
42362
42918
|
}
|
|
42363
42919
|
|
|
42364
42920
|
/**
|
|
@@ -42523,7 +43079,11 @@ class SegTrack extends TrackBase {
|
|
|
42523
43079
|
|
|
42524
43080
|
// this.featureSource = config.sourceType === "bigquery" ?
|
|
42525
43081
|
// new igv.BigQueryFeatureSource(this.config) :
|
|
42526
|
-
|
|
43082
|
+
|
|
43083
|
+
// Disable whole genome downsampling unless explicitly.
|
|
43084
|
+
const configCopy = Object.assign({}, this.config);
|
|
43085
|
+
configCopy.maxWGCount = configCopy.maxWGCount || Number.MAX_SAFE_INTEGER;
|
|
43086
|
+
this.featureSource = FeatureSource(configCopy, this.browser.genome);
|
|
42527
43087
|
|
|
42528
43088
|
this.initialSort = config.sort;
|
|
42529
43089
|
}
|
|
@@ -43173,6 +43733,19 @@ function autoscale(chr, featureArrays) {
|
|
|
43173
43733
|
* THE SOFTWARE.
|
|
43174
43734
|
*/
|
|
43175
43735
|
|
|
43736
|
+
function getArcType(config) {
|
|
43737
|
+
if (!config.arcType) {
|
|
43738
|
+
return "nested"
|
|
43739
|
+
}
|
|
43740
|
+
switch (config.arcType) {
|
|
43741
|
+
case "chiapet":
|
|
43742
|
+
return "inView"
|
|
43743
|
+
case "chiapetoutbound":
|
|
43744
|
+
return "partialInView"
|
|
43745
|
+
default:
|
|
43746
|
+
return config.arcType
|
|
43747
|
+
}
|
|
43748
|
+
}
|
|
43176
43749
|
|
|
43177
43750
|
class InteractionTrack extends TrackBase {
|
|
43178
43751
|
|
|
@@ -43187,13 +43760,14 @@ class InteractionTrack extends TrackBase {
|
|
|
43187
43760
|
this.sinTheta = Math.sin(this.theta);
|
|
43188
43761
|
this.cosTheta = Math.cos(this.theta);
|
|
43189
43762
|
this.height = config.height || 250;
|
|
43190
|
-
this.arcType = config
|
|
43763
|
+
this.arcType = getArcType(config); // nested | proportional | inView | partialInView
|
|
43191
43764
|
this.arcOrientation = (config.arcOrientation === undefined ? true : config.arcOrientation); // true for up, false for down
|
|
43192
43765
|
this.showBlocks = config.showBlocks === undefined ? true : config.showBlocks;
|
|
43193
43766
|
this.blockHeight = config.blockHeight || 3;
|
|
43194
43767
|
this.thickness = config.thickness || 1;
|
|
43195
43768
|
this.color = config.color || "rgb(180,25,137)";
|
|
43196
|
-
this.alpha = config.alpha || 0.15
|
|
43769
|
+
this.alpha = config.alpha || 0.02; // was: 0.15
|
|
43770
|
+
this.painter = {flipAxis: !this.arcOrientation, dataRange: this.dataRange, paintAxis: paintAxis};
|
|
43197
43771
|
|
|
43198
43772
|
if (config.valueColumn) {
|
|
43199
43773
|
this.valueColumn = config.valueColumn;
|
|
@@ -43258,6 +43832,8 @@ class InteractionTrack extends TrackBase {
|
|
|
43258
43832
|
|
|
43259
43833
|
if (this.arcType === "proportional") {
|
|
43260
43834
|
this.drawProportional(options);
|
|
43835
|
+
} else if (this.arcType === "inView" || this.arcType === "partialInView") {
|
|
43836
|
+
this.drawProportional(options);
|
|
43261
43837
|
} else {
|
|
43262
43838
|
this.drawNested(options);
|
|
43263
43839
|
}
|
|
@@ -43289,6 +43865,9 @@ class InteractionTrack extends TrackBase {
|
|
|
43289
43865
|
|
|
43290
43866
|
for (let feature of featureList) {
|
|
43291
43867
|
|
|
43868
|
+
// Reset transient property drawState. An undefined value => feature has not been drawn.
|
|
43869
|
+
feature.drawState = undefined;
|
|
43870
|
+
|
|
43292
43871
|
let color = feature.color || this.color;
|
|
43293
43872
|
if (color && this.config.useScore) {
|
|
43294
43873
|
color = getAlphaColor(color, scoreShade(feature.score));
|
|
@@ -43358,7 +43937,10 @@ class InteractionTrack extends TrackBase {
|
|
|
43358
43937
|
}
|
|
43359
43938
|
const otherChr = feature.chr === feature.chr1 ? feature.chr2 : feature.chr1;
|
|
43360
43939
|
ctx.strokeStyle = color;
|
|
43361
|
-
|
|
43940
|
+
// get a sense of trans "spread"
|
|
43941
|
+
ctx.fillStyle = getAlphaColor(getChrColor(otherChr), 0.5);
|
|
43942
|
+
// ctx.fillStyle = color
|
|
43943
|
+
|
|
43362
43944
|
if (direction) {
|
|
43363
43945
|
// UP
|
|
43364
43946
|
ctx.fillRect(pixelStart, this.height / 2, w, this.height / 2);
|
|
@@ -43392,6 +43974,11 @@ class InteractionTrack extends TrackBase {
|
|
|
43392
43974
|
}
|
|
43393
43975
|
}
|
|
43394
43976
|
|
|
43977
|
+
getScaleFactor(min, max, height, logScale) {
|
|
43978
|
+
const scale = logScale ? height / (Math.log10(max + 1) - (min <= 0 ? 0 : Math.log10(min + 1))) : height / (max - min);
|
|
43979
|
+
return scale
|
|
43980
|
+
}
|
|
43981
|
+
|
|
43395
43982
|
drawProportional(options) {
|
|
43396
43983
|
|
|
43397
43984
|
const ctx = options.context;
|
|
@@ -43400,12 +43987,9 @@ class InteractionTrack extends TrackBase {
|
|
|
43400
43987
|
const bpPerPixel = options.bpPerPixel;
|
|
43401
43988
|
const bpStart = options.bpStart;
|
|
43402
43989
|
const xScale = bpPerPixel;
|
|
43990
|
+
const refStart = options.referenceFrame.start;
|
|
43991
|
+
const refEnd = options.referenceFrame.end;
|
|
43403
43992
|
|
|
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
43993
|
|
|
43410
43994
|
IGVGraphics.fillRect(ctx, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
43411
43995
|
|
|
@@ -43413,37 +43997,65 @@ class InteractionTrack extends TrackBase {
|
|
|
43413
43997
|
|
|
43414
43998
|
if (featureList && featureList.length > 0) {
|
|
43415
43999
|
|
|
43416
|
-
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
44000
|
+
// we use the min as a filter but not moving the axis
|
|
44001
|
+
const effectiveMin = 0;
|
|
44002
|
+
const yScale = this.getScaleFactor(effectiveMin, this.dataRange.max, options.pixelHeight - 1, this.logScale);
|
|
43420
44003
|
const y = this.arcOrientation ? options.pixelHeight : 0;
|
|
43421
44004
|
|
|
43422
44005
|
for (let feature of featureList) {
|
|
43423
44006
|
|
|
44007
|
+
// Reset transient property drawState. An undefined value => feature has not been drawn.
|
|
44008
|
+
feature.drawState = undefined;
|
|
44009
|
+
|
|
43424
44010
|
const value = this.valueColumn ? feature[this.valueColumn] : feature.score;
|
|
43425
44011
|
if (value === undefined || Number.isNaN(value)) continue
|
|
43426
44012
|
|
|
43427
|
-
const radiusY = this.logScale ?
|
|
43428
|
-
Math.log10(value + 1) * yScale :
|
|
43429
|
-
value * yScale;
|
|
44013
|
+
const radiusY = Math.round((this.logScale ? Math.log10(value + 1) : value) * yScale);
|
|
43430
44014
|
|
|
43431
44015
|
if (feature.chr1 === feature.chr2 || feature.chr === 'all') {
|
|
43432
44016
|
|
|
43433
44017
|
const {m1, m2} = getMidpoints(feature, this.browser.genome);
|
|
43434
44018
|
|
|
43435
|
-
let pixelStart = (m1 - bpStart) / xScale;
|
|
43436
|
-
let pixelEnd = (m2 - bpStart) / xScale;
|
|
44019
|
+
let pixelStart = Math.round((m1 - bpStart) / xScale);
|
|
44020
|
+
let pixelEnd = Math.round((m2 - bpStart) / xScale);
|
|
43437
44021
|
let w = (pixelEnd - pixelStart);
|
|
43438
44022
|
if (w < 3) {
|
|
43439
44023
|
w = 3;
|
|
43440
44024
|
pixelStart--;
|
|
43441
44025
|
}
|
|
43442
44026
|
|
|
43443
|
-
|
|
44027
|
+
// Various filters
|
|
44028
|
+
if (value < this.dataRange.min || value > this.dataRange.max) continue
|
|
44029
|
+
if ("proportional" !== this.arcType) {
|
|
44030
|
+
const showOutbound = (this.arcType === "partialInView");
|
|
44031
|
+
const within = (m1 >= refStart && m2 <= refEnd);
|
|
44032
|
+
let outBound = false;
|
|
44033
|
+
let inBound = false;
|
|
44034
|
+
if (!within && showOutbound) {
|
|
44035
|
+
outBound = (refStart <= m1 && m1 <= refEnd);
|
|
44036
|
+
if (!outBound) inBound = (refStart <= m2 && m2 <= refEnd);
|
|
44037
|
+
}
|
|
44038
|
+
if (!(within || outBound || inBound)) continue
|
|
44039
|
+
}
|
|
44040
|
+
|
|
43444
44041
|
|
|
43445
44042
|
const radiusX = w / 2;
|
|
43446
44043
|
const xc = pixelStart + w / 2;
|
|
44044
|
+
feature.drawState = {xc, yc: y, radiusX, radiusY};
|
|
44045
|
+
|
|
44046
|
+
// const arcKey = ((pixelStart << 16) | pixelEnd)
|
|
44047
|
+
// let arc = arcCaches.get(arcKey)
|
|
44048
|
+
// if (arc !== undefined) {
|
|
44049
|
+
// if (arc.has(radiusY)) {
|
|
44050
|
+
// continue
|
|
44051
|
+
// }
|
|
44052
|
+
// arc.add(radiusY)
|
|
44053
|
+
// } else {
|
|
44054
|
+
// let arcHeights = new Set()
|
|
44055
|
+
// arcHeights.add(radiusY)
|
|
44056
|
+
// arcCaches.set(arcKey, arcHeights)
|
|
44057
|
+
// }
|
|
44058
|
+
|
|
43447
44059
|
const counterClockwise = this.arcOrientation ? true : false;
|
|
43448
44060
|
const color = feature.color || this.color;
|
|
43449
44061
|
ctx.strokeStyle = color;
|
|
@@ -43457,6 +44069,15 @@ class InteractionTrack extends TrackBase {
|
|
|
43457
44069
|
ctx.stroke();
|
|
43458
44070
|
}
|
|
43459
44071
|
|
|
44072
|
+
if (this.alpha) {
|
|
44073
|
+
ctx.fillStyle = getAlphaColor(color, this.alpha);
|
|
44074
|
+
if (true === ctx.isSVG) {
|
|
44075
|
+
ctx.fillEllipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise);
|
|
44076
|
+
} else {
|
|
44077
|
+
ctx.fill();
|
|
44078
|
+
}
|
|
44079
|
+
}
|
|
44080
|
+
|
|
43460
44081
|
if (this.showBlocks && feature.chr !== 'all') {
|
|
43461
44082
|
ctx.fillStyle = color;
|
|
43462
44083
|
const s1 = (feature.start1 - bpStart) / xScale;
|
|
@@ -43468,21 +44089,11 @@ class InteractionTrack extends TrackBase {
|
|
|
43468
44089
|
ctx.fillRect(s2, y, e2 - s2, hb);
|
|
43469
44090
|
}
|
|
43470
44091
|
|
|
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
44092
|
} else {
|
|
44093
|
+
// Inter chromosome
|
|
43483
44094
|
let pixelStart = Math.round((feature.start - bpStart) / xScale);
|
|
43484
44095
|
let pixelEnd = Math.round((feature.end - bpStart) / xScale);
|
|
43485
|
-
if (pixelEnd < 0 || pixelStart > pixelWidth || value < this.dataRange.min) continue
|
|
44096
|
+
if (pixelEnd < 0 || pixelStart > pixelWidth || value < this.dataRange.min || value > this.dataRange.max) continue
|
|
43486
44097
|
|
|
43487
44098
|
const h = Math.min(radiusY, this.height - 13); // Leave room for text
|
|
43488
44099
|
let w = (pixelEnd - pixelStart);
|
|
@@ -43493,6 +44104,8 @@ class InteractionTrack extends TrackBase {
|
|
|
43493
44104
|
const otherChr = feature.chr === feature.chr1 ? feature.chr2 : feature.chr1;
|
|
43494
44105
|
ctx.font = "8px sans-serif";
|
|
43495
44106
|
ctx.textAlign = "center";
|
|
44107
|
+
// get a sense of trans "spread"
|
|
44108
|
+
ctx.fillStyle = getAlphaColor(getChrColor(otherChr), 0.5);
|
|
43496
44109
|
if (this.arcOrientation) {
|
|
43497
44110
|
// UP
|
|
43498
44111
|
const y = this.height - h;
|
|
@@ -43509,6 +44122,26 @@ class InteractionTrack extends TrackBase {
|
|
|
43509
44122
|
}
|
|
43510
44123
|
}
|
|
43511
44124
|
|
|
44125
|
+
clearAxis(ctx, pixelWidth, pixelHeight) {
|
|
44126
|
+
IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
44127
|
+
}
|
|
44128
|
+
|
|
44129
|
+
paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
44130
|
+
// dataRane is interpreted differently for interactino tracks -- all arcs are drawn from "zero", irrespective of dataRange.min
|
|
44131
|
+
const axisRange = {min: 0, max: this.dataRange.max};
|
|
44132
|
+
if (this.arcType === "proportional") {
|
|
44133
|
+
this.painter.flipAxis = !this.arcOrientation;
|
|
44134
|
+
this.painter.dataRange = axisRange;
|
|
44135
|
+
this.painter.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
44136
|
+
} else if (this.arcType === "inView" || this.arcType === "partialInView") {
|
|
44137
|
+
this.painter.flipAxis = !this.arcOrientation;
|
|
44138
|
+
this.painter.dataRange = axisRange;
|
|
44139
|
+
this.painter.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
44140
|
+
} else {
|
|
44141
|
+
this.clearAxis(ctx, pixelWidth, pixelHeight);
|
|
44142
|
+
}
|
|
44143
|
+
}
|
|
44144
|
+
|
|
43512
44145
|
menuItemList() {
|
|
43513
44146
|
|
|
43514
44147
|
let items = [
|
|
@@ -43525,10 +44158,13 @@ class InteractionTrack extends TrackBase {
|
|
|
43525
44158
|
if (this.hasValue) {
|
|
43526
44159
|
const lut =
|
|
43527
44160
|
{
|
|
43528
|
-
"nested": "Nested
|
|
43529
|
-
"proportional": "Proportional
|
|
44161
|
+
"nested": "Nested",
|
|
44162
|
+
"proportional": "Proportional - All",
|
|
44163
|
+
"inView": "Proportional - Both Ends in View",
|
|
44164
|
+
"partialInView": "Proportional - One End in View"
|
|
43530
44165
|
};
|
|
43531
|
-
|
|
44166
|
+
items.push("<b>Arc Type</b>");
|
|
44167
|
+
for (let arcType of ["nested", "proportional", "inView", "partialInView"]) {
|
|
43532
44168
|
items.push(
|
|
43533
44169
|
{
|
|
43534
44170
|
object: $$1(createCheckbox$1(lut[arcType], arcType === this.arcType)),
|
|
@@ -43539,45 +44175,37 @@ class InteractionTrack extends TrackBase {
|
|
|
43539
44175
|
});
|
|
43540
44176
|
}
|
|
43541
44177
|
}
|
|
44178
|
+
items.push("<hr/>");
|
|
43542
44179
|
|
|
43543
44180
|
items.push({
|
|
43544
|
-
|
|
44181
|
+
name: "Toggle arc direction",
|
|
43545
44182
|
click: () => {
|
|
43546
|
-
this.
|
|
44183
|
+
this.arcOrientation = !this.arcOrientation;
|
|
43547
44184
|
this.trackView.repaintViews();
|
|
43548
44185
|
}
|
|
43549
44186
|
});
|
|
43550
44187
|
items.push({
|
|
43551
|
-
name: "
|
|
44188
|
+
name: this.showBlocks ? "Hide Blocks" : "Show Blocks",
|
|
43552
44189
|
click: () => {
|
|
43553
|
-
this.
|
|
44190
|
+
this.showBlocks = !this.showBlocks;
|
|
43554
44191
|
this.trackView.repaintViews();
|
|
43555
44192
|
}
|
|
43556
44193
|
});
|
|
43557
44194
|
|
|
43558
|
-
|
|
43559
|
-
|
|
44195
|
+
|
|
44196
|
+
if (this.arcType === "proportional" || this.arcType === "inView" || this.arcType === "partialInView") {
|
|
44197
|
+
// MenuUtils.numericDataMenuItems(this.trackView).forEach(item => items.push(item))
|
|
43560
44198
|
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
43561
44199
|
}
|
|
43562
44200
|
|
|
43563
44201
|
if (this.browser.circularView && true === this.browser.circularViewVisible) {
|
|
44202
|
+
items.push('<hr/>');
|
|
43564
44203
|
items.push({
|
|
43565
44204
|
label: 'Add interactions to circular view',
|
|
43566
44205
|
click: () => {
|
|
43567
|
-
|
|
43568
|
-
const inView = [];
|
|
43569
44206
|
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
|
-
}
|
|
44207
|
+
this.addChordsForViewport(viewport.referenceFrame);
|
|
43576
44208
|
}
|
|
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
44209
|
}
|
|
43582
44210
|
});
|
|
43583
44211
|
}
|
|
@@ -43596,22 +44224,43 @@ class InteractionTrack extends TrackBase {
|
|
|
43596
44224
|
label: 'Add interactions to circular view',
|
|
43597
44225
|
click: () => {
|
|
43598
44226
|
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});
|
|
44227
|
+
// first pass: to get all the relevant features
|
|
44228
|
+
this.addChordsForViewport(refFrame);
|
|
43606
44229
|
}
|
|
43607
44230
|
});
|
|
43608
44231
|
|
|
43609
44232
|
list.push('<hr/>');
|
|
43610
44233
|
return list
|
|
43611
44234
|
}
|
|
43612
|
-
|
|
43613
44235
|
}
|
|
43614
44236
|
|
|
44237
|
+
/**
|
|
44238
|
+
* Add chords to the circular view for the given viewport, represented by its reference frame
|
|
44239
|
+
* @param refFrame
|
|
44240
|
+
*/
|
|
44241
|
+
addChordsForViewport(refFrame) {
|
|
44242
|
+
const cachedFeatures = "all" === refFrame.chr ?
|
|
44243
|
+
this.featureSource.getAllFeatures() :
|
|
44244
|
+
this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
44245
|
+
|
|
44246
|
+
// inView features are simply features that have been drawn, i.e. have a drawState
|
|
44247
|
+
const inView = cachedFeatures.filter(f => f.drawState);
|
|
44248
|
+
if(inView.length === 0) erturn;
|
|
44249
|
+
|
|
44250
|
+
this.browser.circularViewVisible = true;
|
|
44251
|
+
const chords = makeBedPEChords(inView);
|
|
44252
|
+
|
|
44253
|
+
// for filtered set, distinguishing the chromosomes is more critical than tracks
|
|
44254
|
+
const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.5);
|
|
44255
|
+
const trackColor = IGVColor.addAlpha(this.color, 0.5);
|
|
44256
|
+
|
|
44257
|
+
// name the chord set to include filtering information
|
|
44258
|
+
const encodedName = this.name.replaceAll(' ', '%20');
|
|
44259
|
+
const chordSetName = "all" === refFrame.chr ?
|
|
44260
|
+
encodedName :
|
|
44261
|
+
`${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end} ; range:${this.dataRange.min}-${this.dataRange.max})`;
|
|
44262
|
+
this.browser.circularView.addChords(chords, {track: chordSetName, color: chordSetColor, trackColor: trackColor});
|
|
44263
|
+
}
|
|
43615
44264
|
|
|
43616
44265
|
doAutoscale(features) {
|
|
43617
44266
|
|
|
@@ -43678,10 +44327,12 @@ class InteractionTrack extends TrackBase {
|
|
|
43678
44327
|
const featureList = features || clickState.viewport.getCachedFeatures();
|
|
43679
44328
|
const candidates = [];
|
|
43680
44329
|
if (featureList) {
|
|
43681
|
-
const proportional = this.arcType === "proportional";
|
|
44330
|
+
const proportional = (this.arcType === "proportional" || this.arcType === "inView" || this.arcType === "partialInView");
|
|
43682
44331
|
|
|
43683
44332
|
for (let feature of featureList) {
|
|
44333
|
+
|
|
43684
44334
|
if (!feature.drawState) continue
|
|
44335
|
+
|
|
43685
44336
|
if (feature.chr1 === feature.chr2 || feature.chr === 'all') {
|
|
43686
44337
|
if (proportional) {
|
|
43687
44338
|
//(x-xc)^2/radiusX^2 + (y-yc)^2/radiusY^2 <= 1
|
|
@@ -43719,6 +44370,26 @@ class InteractionTrack extends TrackBase {
|
|
|
43719
44370
|
}
|
|
43720
44371
|
return candidates.map((c) => c.feature)
|
|
43721
44372
|
}
|
|
44373
|
+
|
|
44374
|
+
/**
|
|
44375
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
44376
|
+
*
|
|
44377
|
+
* @returns {*|{}}
|
|
44378
|
+
*/
|
|
44379
|
+
getState() {
|
|
44380
|
+
|
|
44381
|
+
const config = super.getState();
|
|
44382
|
+
|
|
44383
|
+
// if (this.height !== undefined) config.height = this.height;
|
|
44384
|
+
if (this.arcType !== undefined) config.arcType = this.arcType;
|
|
44385
|
+
if (this.arcOrientation !== undefined) config.arcOrientation = this.arcOrientation;
|
|
44386
|
+
if (this.showBlocks !== undefined) config.showBlocks = this.showBlocks;
|
|
44387
|
+
if (this.blockHeight !== undefined) config.blockHeight = this.blockHeight;
|
|
44388
|
+
if (this.thickness !== undefined) config.thickness = this.thickness;
|
|
44389
|
+
if (this.alpha !== undefined) config.alpha = this.alpha;
|
|
44390
|
+
|
|
44391
|
+
return config
|
|
44392
|
+
}
|
|
43722
44393
|
}
|
|
43723
44394
|
|
|
43724
44395
|
function getMidpoints(feature, genome) {
|
|
@@ -43782,29 +44453,93 @@ function getAlphaColor(color, alpha) {
|
|
|
43782
44453
|
|
|
43783
44454
|
|
|
43784
44455
|
/**
|
|
43785
|
-
* Called in the context of FeatureSource
|
|
44456
|
+
* Called in the context of FeatureSource (i.e. this == the feature source (a TextFeatureSource) for the track
|
|
44457
|
+
*
|
|
43786
44458
|
* @param allFeatures
|
|
43787
44459
|
* @returns {[]}
|
|
43788
44460
|
*/
|
|
43789
44461
|
function getWGFeatures(allFeatures) {
|
|
43790
44462
|
|
|
44463
|
+
const makeWGFeature = (f) => {
|
|
44464
|
+
const wg = Object.assign({}, f);
|
|
44465
|
+
wg.chr = "all";
|
|
44466
|
+
wg.start = genome.getGenomeCoordinate(f.chr1, f.start1);
|
|
44467
|
+
wg.end = genome.getGenomeCoordinate(f.chr2, f.end2);
|
|
44468
|
+
return wg
|
|
44469
|
+
};
|
|
44470
|
+
|
|
43791
44471
|
const genome = this.genome;
|
|
43792
|
-
|
|
44472
|
+
|
|
44473
|
+
// First pass -- find the max score feature
|
|
44474
|
+
let maxScoreFeature;
|
|
44475
|
+
let totalFeatureCount = 0;
|
|
43793
44476
|
for (let c of genome.wgChromosomeNames) {
|
|
43794
|
-
|
|
44477
|
+
let chrFeatures = allFeatures[c];
|
|
43795
44478
|
if (chrFeatures) {
|
|
43796
44479
|
for (let f of chrFeatures) {
|
|
43797
44480
|
if (!f.dup) {
|
|
43798
|
-
|
|
43799
|
-
|
|
43800
|
-
|
|
43801
|
-
|
|
43802
|
-
|
|
44481
|
+
totalFeatureCount++;
|
|
44482
|
+
if (f.score && (!maxScoreFeature || f.score > maxScoreFeature.score)) {
|
|
44483
|
+
maxScoreFeature = f;
|
|
44484
|
+
}
|
|
44485
|
+
}
|
|
44486
|
+
}
|
|
44487
|
+
}
|
|
44488
|
+
}
|
|
44489
|
+
|
|
44490
|
+
const maxCount = this.maxWGCount;
|
|
44491
|
+
const nBins = maxScoreFeature && maxScoreFeature.score > 0 && totalFeatureCount > maxCount ? 5 : 1; // TODO make a function of total # of features & maxCount?
|
|
44492
|
+
const featuresPerBin = Math.floor(maxCount / nBins);
|
|
44493
|
+
const binSize = maxScoreFeature && maxScoreFeature.score > 0 ? Math.log(maxScoreFeature.score) / nBins : Number.MAX_SAFE_INTEGER;
|
|
44494
|
+
|
|
44495
|
+
let binnedFeatures = [];
|
|
44496
|
+
let counts = [];
|
|
44497
|
+
for (let i = 0; i < nBins; i++) {
|
|
44498
|
+
counts.push([0]);
|
|
44499
|
+
binnedFeatures.push([]);
|
|
44500
|
+
}
|
|
44501
|
+
|
|
44502
|
+
for (let c of genome.wgChromosomeNames) {
|
|
44503
|
+
let chrFeatures = allFeatures[c];
|
|
44504
|
+
if (chrFeatures) {
|
|
44505
|
+
for (let f of chrFeatures) {
|
|
44506
|
+
if (!f.dup) {
|
|
44507
|
+
const bin = f.score ? Math.min(nBins - 1, Math.floor(Math.log(f.score) / binSize)) : 0;
|
|
44508
|
+
if (binnedFeatures[bin].length < featuresPerBin) {
|
|
44509
|
+
binnedFeatures[bin].push(makeWGFeature(f));
|
|
44510
|
+
} else {
|
|
44511
|
+
//Reservoir sampling
|
|
44512
|
+
const samplingProb = featuresPerBin / (counts[bin] + 1);
|
|
44513
|
+
if (Math.random() < samplingProb) {
|
|
44514
|
+
const idx = Math.floor(Math.random() * (featuresPerBin - 1));
|
|
44515
|
+
binnedFeatures[bin][idx] = makeWGFeature(f);
|
|
44516
|
+
}
|
|
44517
|
+
}
|
|
44518
|
+
counts[bin]++;
|
|
43803
44519
|
}
|
|
43804
44520
|
}
|
|
43805
44521
|
}
|
|
43806
44522
|
}
|
|
43807
44523
|
|
|
44524
|
+
let wgFeatures;
|
|
44525
|
+
if (nBins === 1) {
|
|
44526
|
+
wgFeatures = binnedFeatures[0];
|
|
44527
|
+
} else {
|
|
44528
|
+
wgFeatures = [];
|
|
44529
|
+
for (let bf of binnedFeatures) {
|
|
44530
|
+
for (let f of bf) wgFeatures.push(f);
|
|
44531
|
+
}
|
|
44532
|
+
// Keep the feature with max score
|
|
44533
|
+
if (maxScoreFeature) {
|
|
44534
|
+
wgFeatures.push(makeWGFeature(maxScoreFeature));
|
|
44535
|
+
}
|
|
44536
|
+
wgFeatures.sort(function (a, b) {
|
|
44537
|
+
return a.start - b.start
|
|
44538
|
+
});
|
|
44539
|
+
console.log(wgFeatures.length);
|
|
44540
|
+
}
|
|
44541
|
+
|
|
44542
|
+
|
|
43808
44543
|
return wgFeatures
|
|
43809
44544
|
}
|
|
43810
44545
|
|
|
@@ -44876,7 +45611,6 @@ class GWASTrack extends TrackBase {
|
|
|
44876
45611
|
this.divider = config.divider || "rgb(225,225,225)";
|
|
44877
45612
|
this.dotSize = config.dotSize || 3;
|
|
44878
45613
|
this.popoverWindow = (config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow);
|
|
44879
|
-
this.description = config.description; // might be null
|
|
44880
45614
|
|
|
44881
45615
|
this.colorScales = config.color ?
|
|
44882
45616
|
new ConstantColorScale(config.color) :
|
|
@@ -46428,12 +47162,6 @@ class SpliceJunctionTrack extends TrackBase {
|
|
|
46428
47162
|
return data
|
|
46429
47163
|
}
|
|
46430
47164
|
|
|
46431
|
-
|
|
46432
|
-
description() {
|
|
46433
|
-
return this.name
|
|
46434
|
-
|
|
46435
|
-
}
|
|
46436
|
-
|
|
46437
47165
|
/**
|
|
46438
47166
|
* Called when the track is removed. Do any needed cleanup here
|
|
46439
47167
|
*/
|
|
@@ -47000,7 +47728,7 @@ class ReferenceFrame {
|
|
|
47000
47728
|
this.end = end;
|
|
47001
47729
|
|
|
47002
47730
|
this.bpPerPixel = bpPerPixel;
|
|
47003
|
-
this.id = guid$
|
|
47731
|
+
this.id = guid$2();
|
|
47004
47732
|
}
|
|
47005
47733
|
|
|
47006
47734
|
calculateEnd(pixels) {
|
|
@@ -47722,7 +48450,7 @@ class CursorGuide {
|
|
|
47722
48450
|
|
|
47723
48451
|
this.addMouseHandler(browser);
|
|
47724
48452
|
|
|
47725
|
-
this.setVisibility(browser.config.
|
|
48453
|
+
this.setVisibility(browser.config.showCursorGuide);
|
|
47726
48454
|
|
|
47727
48455
|
}
|
|
47728
48456
|
|
|
@@ -47739,35 +48467,40 @@ class CursorGuide {
|
|
|
47739
48467
|
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
47740
48468
|
|
|
47741
48469
|
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
48470
|
|
|
47748
|
-
if (
|
|
48471
|
+
if (target.parentElement) {
|
|
47749
48472
|
|
|
47750
|
-
|
|
48473
|
+
if (target.parentElement.classList.contains('igv-viewport-content')) {
|
|
48474
|
+
viewport = target.parentElement.parentElement;
|
|
48475
|
+
} else if (target.parentElement.classList.contains('igv-viewport') && target.classList.contains('igv-viewport-content')) {
|
|
48476
|
+
viewport = target.parentElement;
|
|
48477
|
+
}
|
|
48478
|
+
|
|
48479
|
+
if (viewport && browser.getRulerTrackView()) {
|
|
48480
|
+
|
|
48481
|
+
this.verticalGuide.style.left = `${x}px`;
|
|
47751
48482
|
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
|
|
47755
|
-
|
|
47756
|
-
|
|
47757
|
-
|
|
48483
|
+
const columns = browser.root.querySelectorAll('.igv-column');
|
|
48484
|
+
let index = undefined;
|
|
48485
|
+
const viewportParent = viewport.parentElement;
|
|
48486
|
+
for (let i = 0; i < columns.length; i++) {
|
|
48487
|
+
if (undefined === index && viewportParent === columns[i]) {
|
|
48488
|
+
index = i;
|
|
48489
|
+
}
|
|
47758
48490
|
}
|
|
47759
|
-
}
|
|
47760
48491
|
|
|
47761
|
-
|
|
47762
|
-
|
|
48492
|
+
const rulerViewport = browser.getRulerTrackView().viewports[index];
|
|
48493
|
+
const result = rulerViewport.mouseMove(event);
|
|
47763
48494
|
|
|
47764
|
-
|
|
48495
|
+
if (result) {
|
|
47765
48496
|
|
|
47766
|
-
|
|
47767
|
-
|
|
48497
|
+
const {start, bp, end} = result;
|
|
48498
|
+
const interpolant = (bp - start) / (end - start);
|
|
48499
|
+
|
|
48500
|
+
if (this.customMouseHandler) {
|
|
48501
|
+
this.customMouseHandler({start, bp, end, interpolant});
|
|
48502
|
+
}
|
|
47768
48503
|
|
|
47769
|
-
if (this.customMouseHandler) {
|
|
47770
|
-
this.customMouseHandler({start, bp, end, interpolant});
|
|
47771
48504
|
}
|
|
47772
48505
|
|
|
47773
48506
|
}
|
|
@@ -47781,8 +48514,8 @@ class CursorGuide {
|
|
|
47781
48514
|
this.columnContainer.removeEventListener('mousemove', this.boundMouseMoveHandler);
|
|
47782
48515
|
}
|
|
47783
48516
|
|
|
47784
|
-
setVisibility(
|
|
47785
|
-
if (true ===
|
|
48517
|
+
setVisibility(showCursorGuide) {
|
|
48518
|
+
if (true === showCursorGuide) {
|
|
47786
48519
|
this.show();
|
|
47787
48520
|
} else {
|
|
47788
48521
|
this.hide();
|
|
@@ -47953,50 +48686,52 @@ class CenterLineButton {
|
|
|
47953
48686
|
* THE SOFTWARE.
|
|
47954
48687
|
*/
|
|
47955
48688
|
|
|
47956
|
-
|
|
48689
|
+
class TrackLabelControl {
|
|
47957
48690
|
|
|
47958
|
-
|
|
47959
|
-
parent.appendChild(this.button);
|
|
47960
|
-
this.button.textContent = 'track labels';
|
|
48691
|
+
constructor(parent, browser) {
|
|
47961
48692
|
|
|
47962
|
-
|
|
47963
|
-
|
|
47964
|
-
this.
|
|
47965
|
-
browser.setTrackLabelVisibility(browser.trackLabelsVisible);
|
|
47966
|
-
});
|
|
48693
|
+
this.button = div$1({class: 'igv-navbar-button'});
|
|
48694
|
+
parent.appendChild(this.button);
|
|
48695
|
+
this.button.textContent = 'track labels';
|
|
47967
48696
|
|
|
47968
|
-
|
|
48697
|
+
this.button.addEventListener('click', () => {
|
|
48698
|
+
browser.trackLabelsVisible = !browser.trackLabelsVisible;
|
|
48699
|
+
this.setState(browser.trackLabelsVisible);
|
|
48700
|
+
browser.setTrackLabelVisibility(browser.trackLabelsVisible);
|
|
48701
|
+
});
|
|
47969
48702
|
|
|
47970
|
-
|
|
48703
|
+
this.browser = browser;
|
|
47971
48704
|
|
|
47972
|
-
|
|
48705
|
+
this.setVisibility(browser.config.showTrackLabelButton);
|
|
47973
48706
|
|
|
47974
|
-
|
|
48707
|
+
this.setState(browser.trackLabelsVisible);
|
|
48708
|
+
}
|
|
47975
48709
|
|
|
47976
|
-
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
47980
|
-
|
|
48710
|
+
setVisibility(showTrackLabelButton) {
|
|
48711
|
+
if (true === showTrackLabelButton) {
|
|
48712
|
+
this.show();
|
|
48713
|
+
} else {
|
|
48714
|
+
this.hide();
|
|
48715
|
+
}
|
|
47981
48716
|
}
|
|
47982
|
-
};
|
|
47983
48717
|
|
|
47984
|
-
|
|
47985
|
-
|
|
47986
|
-
|
|
47987
|
-
|
|
47988
|
-
|
|
48718
|
+
setState(trackLabelsVisible) {
|
|
48719
|
+
if (true === trackLabelsVisible) {
|
|
48720
|
+
this.button.classList.add('igv-navbar-button-clicked');
|
|
48721
|
+
} else {
|
|
48722
|
+
this.button.classList.remove('igv-navbar-button-clicked');
|
|
48723
|
+
}
|
|
47989
48724
|
}
|
|
47990
|
-
};
|
|
47991
48725
|
|
|
47992
|
-
|
|
47993
|
-
|
|
47994
|
-
|
|
47995
|
-
}
|
|
48726
|
+
show() {
|
|
48727
|
+
this.button.style.display = 'block';
|
|
48728
|
+
this.setState(this.browser.trackLabelsVisible);
|
|
48729
|
+
}
|
|
47996
48730
|
|
|
47997
|
-
|
|
47998
|
-
|
|
47999
|
-
}
|
|
48731
|
+
hide() {
|
|
48732
|
+
this.button.style.display = 'none';
|
|
48733
|
+
}
|
|
48734
|
+
}
|
|
48000
48735
|
|
|
48001
48736
|
/*
|
|
48002
48737
|
* The MIT License (MIT)
|
|
@@ -48281,55 +49016,6 @@ const SVGSaveControl = function (parent, browser) {
|
|
|
48281
49016
|
button.addEventListener('click', () => browser.saveSVGtoFile({}));
|
|
48282
49017
|
};
|
|
48283
49018
|
|
|
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
49019
|
/*
|
|
48334
49020
|
* The MIT License (MIT)
|
|
48335
49021
|
*
|
|
@@ -48711,6 +49397,18 @@ CircularViewControl.prototype.hide = function () {
|
|
|
48711
49397
|
this.button.style.display = 'none';
|
|
48712
49398
|
};
|
|
48713
49399
|
|
|
49400
|
+
/**
|
|
49401
|
+
* User supplied button for the navbar
|
|
49402
|
+
*/
|
|
49403
|
+
|
|
49404
|
+
const CustomButton = function (parent, browser, b) {
|
|
49405
|
+
|
|
49406
|
+
const button = div$1({class: 'igv-navbar-button'});
|
|
49407
|
+
parent.append(button);
|
|
49408
|
+
button.textContent = b.label;
|
|
49409
|
+
button.addEventListener('click', () => b.callback(browser));
|
|
49410
|
+
};
|
|
49411
|
+
|
|
48714
49412
|
/*
|
|
48715
49413
|
* The MIT License (MIT)
|
|
48716
49414
|
*
|
|
@@ -48756,7 +49454,7 @@ class Browser {
|
|
|
48756
49454
|
constructor(config, parentDiv) {
|
|
48757
49455
|
|
|
48758
49456
|
this.config = config;
|
|
48759
|
-
this.guid = guid$
|
|
49457
|
+
this.guid = guid$2();
|
|
48760
49458
|
this.namespace = '.browser_' + this.guid;
|
|
48761
49459
|
|
|
48762
49460
|
this.parent = parentDiv;
|
|
@@ -48808,7 +49506,7 @@ class Browser {
|
|
|
48808
49506
|
|
|
48809
49507
|
this.isCenterLineVisible = config.showCenterGuide;
|
|
48810
49508
|
|
|
48811
|
-
this.cursorGuideVisible = config.
|
|
49509
|
+
this.cursorGuideVisible = config.showCursorGuide;
|
|
48812
49510
|
|
|
48813
49511
|
this.showSampleNames = config.showSampleNames;
|
|
48814
49512
|
this.showSampleNameButton = config.showSampleNameButton;
|
|
@@ -48921,6 +49619,12 @@ class Browser {
|
|
|
48921
49619
|
this.svgSaveControl = new SVGSaveControl($toggle_button_container.get(0), this);
|
|
48922
49620
|
}
|
|
48923
49621
|
|
|
49622
|
+
if(config.customButtons) {
|
|
49623
|
+
for(let b of config.customButtons) {
|
|
49624
|
+
new CustomButton($toggle_button_container.get(0), this, b);
|
|
49625
|
+
}
|
|
49626
|
+
}
|
|
49627
|
+
|
|
48924
49628
|
this.zoomWidget = new ZoomWidget(this, $navbarRightContainer.get(0));
|
|
48925
49629
|
|
|
48926
49630
|
if (false === config.showNavigation) {
|
|
@@ -48928,13 +49632,13 @@ class Browser {
|
|
|
48928
49632
|
}
|
|
48929
49633
|
|
|
48930
49634
|
this.inputDialog = new InputDialog(this.root);
|
|
48931
|
-
this.inputDialog.container.id = `igv-input-dialog-${guid$
|
|
49635
|
+
this.inputDialog.container.id = `igv-input-dialog-${guid$2()}`;
|
|
48932
49636
|
|
|
48933
49637
|
this.dataRangeDialog = new DataRangeDialog($$1(this.root));
|
|
48934
|
-
this.dataRangeDialog.$container.get(0).id = `igv-data-range-dialog-${guid$
|
|
49638
|
+
this.dataRangeDialog.$container.get(0).id = `igv-data-range-dialog-${guid$2()}`;
|
|
48935
49639
|
|
|
48936
49640
|
this.genericColorPicker = new GenericColorPicker({parent: this.columnContainer, width: 432});
|
|
48937
|
-
this.genericColorPicker.container.id = `igv-track-color-picker-${guid$
|
|
49641
|
+
this.genericColorPicker.container.id = `igv-track-color-picker-${guid$2()}`;
|
|
48938
49642
|
|
|
48939
49643
|
return $navBar
|
|
48940
49644
|
|
|
@@ -49963,46 +50667,6 @@ class Browser {
|
|
|
49963
50667
|
|
|
49964
50668
|
}
|
|
49965
50669
|
|
|
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
50670
|
async selectMultiLocusPanel(referenceFrame) {
|
|
50007
50671
|
|
|
50008
50672
|
const referenceFrameIndex = this.referenceFrameList.indexOf(referenceFrame);
|
|
@@ -50226,6 +50890,7 @@ class Browser {
|
|
|
50226
50890
|
// Build locus array (multi-locus view). Use the first track to extract the loci, any track could be used.
|
|
50227
50891
|
const locus = [];
|
|
50228
50892
|
const gtexSelections = {};
|
|
50893
|
+
let hasGtexSelections = false;
|
|
50229
50894
|
let anyTrackView = this.trackViews[0];
|
|
50230
50895
|
for (let {referenceFrame} of anyTrackView.viewports) {
|
|
50231
50896
|
const locusString = referenceFrame.getLocusString();
|
|
@@ -50236,12 +50901,11 @@ class Browser {
|
|
|
50236
50901
|
snp: referenceFrame.selection.snp
|
|
50237
50902
|
};
|
|
50238
50903
|
gtexSelections[locusString] = selection;
|
|
50904
|
+
hasGtexSelections = true;
|
|
50239
50905
|
}
|
|
50240
50906
|
}
|
|
50241
50907
|
json["locus"] = locus.length === 1 ? locus[0] : locus;
|
|
50242
|
-
|
|
50243
|
-
const gtexKeys = Object.getOwnPropertyNames(gtexSelections);
|
|
50244
|
-
if (gtexKeys.length > 0) {
|
|
50908
|
+
if (hasGtexSelections) {
|
|
50245
50909
|
json["gtexSelections"] = gtexSelections;
|
|
50246
50910
|
}
|
|
50247
50911
|
|
|
@@ -50265,27 +50929,21 @@ class Browser {
|
|
|
50265
50929
|
trackJson.push(config);
|
|
50266
50930
|
}
|
|
50267
50931
|
} catch (e) {
|
|
50268
|
-
|
|
50932
|
+
console.error(`Track: ${track.name}: ${e}`);
|
|
50933
|
+
errors.push(`Track: ${track.name}: ${e}`);
|
|
50269
50934
|
}
|
|
50270
50935
|
}
|
|
50271
50936
|
|
|
50272
50937
|
if (errors.length > 0) {
|
|
50273
50938
|
let n = 1;
|
|
50274
|
-
let message = 'Errors encountered saving session:';
|
|
50939
|
+
let message = 'Errors encountered saving session: </br>';
|
|
50275
50940
|
for (let e of errors) {
|
|
50276
|
-
message += ` (${n++}) ${e.toString()}
|
|
50941
|
+
message += ` (${n++}) ${e.toString()} <br/>`;
|
|
50277
50942
|
}
|
|
50278
50943
|
throw Error(message)
|
|
50279
50944
|
}
|
|
50280
50945
|
|
|
50281
50946
|
|
|
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
50947
|
|
|
50290
50948
|
json["tracks"] = trackJson;
|
|
50291
50949
|
|
|
@@ -50673,7 +51331,7 @@ async function createBrowser(parentDiv, config) {
|
|
|
50673
51331
|
|
|
50674
51332
|
setDefaults(config);
|
|
50675
51333
|
|
|
50676
|
-
if (config.queryParametersSupported
|
|
51334
|
+
if (config.queryParametersSupported) {
|
|
50677
51335
|
extractQuery(config);
|
|
50678
51336
|
}
|
|
50679
51337
|
if (config.apiKey) {
|
|
@@ -50737,10 +51395,6 @@ async function visibilityChange() {
|
|
|
50737
51395
|
|
|
50738
51396
|
function setDefaults(config) {
|
|
50739
51397
|
|
|
50740
|
-
if (undefined === config.promisified) {
|
|
50741
|
-
config.promisified = false;
|
|
50742
|
-
}
|
|
50743
|
-
|
|
50744
51398
|
if (undefined === config.minimumBases) {
|
|
50745
51399
|
config.minimumBases = 40;
|
|
50746
51400
|
}
|
|
@@ -50769,8 +51423,9 @@ function setDefaults(config) {
|
|
|
50769
51423
|
config.showCursorTrackingGuideButton = true;
|
|
50770
51424
|
}
|
|
50771
51425
|
|
|
50772
|
-
|
|
50773
|
-
|
|
51426
|
+
|
|
51427
|
+
if (undefined === config.showCursorGuide) {
|
|
51428
|
+
config.showCursorGuide = config.showCursorTrackingGuide || false; // showCursorTrackingGuide is a synonym
|
|
50774
51429
|
}
|
|
50775
51430
|
|
|
50776
51431
|
if (undefined === config.showCenterGuideButton) {
|
|
@@ -50861,6 +51516,8 @@ function extractQuery(config) {
|
|
|
50861
51516
|
config[key] = value;
|
|
50862
51517
|
}
|
|
50863
51518
|
i = j + 1;
|
|
51519
|
+
} else {
|
|
51520
|
+
i++;
|
|
50864
51521
|
}
|
|
50865
51522
|
}
|
|
50866
51523
|
}
|
|
@@ -50897,7 +51554,7 @@ async function createTrack(config, browser) {
|
|
|
50897
51554
|
|
|
50898
51555
|
function embedCSS() {
|
|
50899
51556
|
|
|
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';
|
|
51557
|
+
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
51558
|
|
|
50902
51559
|
var style = document.createElement('style');
|
|
50903
51560
|
style.setAttribute('type', 'text/css');
|