igv 2.11.0 → 2.12.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/README.md +10 -23
- package/dist/igv.esm.js +1002 -1124
- package/dist/igv.esm.min.js +9 -9
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +991 -1048
- package/dist/igv.min.js +10 -10
- package/dist/igv.min.js.map +1 -1
- package/package.json +4 -4
package/dist/igv.js
CHANGED
|
@@ -17943,7 +17943,7 @@
|
|
|
17943
17943
|
* @constructor
|
|
17944
17944
|
*/
|
|
17945
17945
|
|
|
17946
|
-
class FeatureCache {
|
|
17946
|
+
class FeatureCache$1 {
|
|
17947
17947
|
constructor(featureList, genome, range) {
|
|
17948
17948
|
featureList = featureList || [];
|
|
17949
17949
|
this.treeMap = this.buildTreeMap(featureList, genome);
|
|
@@ -19385,7 +19385,7 @@
|
|
|
19385
19385
|
}
|
|
19386
19386
|
|
|
19387
19387
|
function embedCSS$2() {
|
|
19388
|
-
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';
|
|
19388
|
+
var css = '.igv-ui-popover {\n cursor: default;\n position: absolute;\n z-index: 2048;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n background-color: white; }\n .igv-ui-popover > div:first-child {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-popover > div:first-child > div:first-child {\n margin-left: 4px; }\n .igv-ui-popover > div:first-child > div:last-child {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-popover > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-popover > div:last-child {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: 400px;\n max-width: 800px;\n background-color: white; }\n .igv-ui-popover > div:last-child > div {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n margin-left: 4px;\n margin-right: 4px;\n min-width: 220px;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n .igv-ui-popover > div:last-child > div > span {\n font-weight: bolder; }\n .igv-ui-popover > div:last-child hr {\n width: 100%; }\n\n.igv-ui-alert-dialog-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n top: 50%;\n left: 50%;\n width: 400px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n outline: none;\n font-family: \"Open Sans\", sans-serif;\n font-size: 15px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:first-child {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-alert-dialog-container > div:first-child div:first-child {\n padding-left: 8px; }\n .igv-ui-alert-dialog-container .igv-ui-alert-dialog-body {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n color: #373737;\n width: 100%;\n height: calc(100% - 24px - 64px);\n overflow-y: scroll; }\n .igv-ui-alert-dialog-container .igv-ui-alert-dialog-body .igv-ui-alert-dialog-body-copy {\n margin: 16px;\n width: auto;\n height: auto;\n overflow-wrap: break-word;\n word-break: break-word;\n background-color: white;\n border: unset; }\n .igv-ui-alert-dialog-container > div:last-child {\n width: 100%;\n margin-bottom: 10px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center; }\n .igv-ui-alert-dialog-container > div:last-child div {\n margin: unset;\n width: 40px;\n height: 30px;\n line-height: 30px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n border-color: #2B81AF;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-alert-dialog-container > div:last-child div:hover {\n cursor: pointer;\n border-color: #25597f;\n background-color: #25597f; }\n\n.igv-ui-color-swatch {\n position: relative;\n box-sizing: content-box;\n display: flex;\n flex-flow: row;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n width: 32px;\n height: 32px;\n border-style: solid;\n border-width: 2px;\n border-color: white;\n border-radius: 4px; }\n\n.igv-ui-color-swatch:hover {\n border-color: dimgray; }\n\n.igv-ui-colorpicker-menu-close-button {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 32px;\n margin-top: 4px;\n margin-bottom: 4px;\n padding-right: 8px; }\n .igv-ui-colorpicker-menu-close-button i.fa {\n display: block;\n margin-left: 4px;\n margin-right: 4px;\n color: #5f5f5f; }\n .igv-ui-colorpicker-menu-close-button i.fa:hover,\n .igv-ui-colorpicker-menu-close-button i.fa:focus,\n .igv-ui-colorpicker-menu-close-button i.fa:active {\n cursor: pointer;\n color: #0f0f0f; }\n\n.igv-ui-generic-dialog-container {\n box-sizing: content-box;\n position: fixed;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n font-size: 16px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-generic-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center; }\n .igv-ui-generic-container > div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd; }\n .igv-ui-generic-container > div:first-child > div {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px; }\n\n.igv-ui-dialog {\n z-index: 2048;\n position: fixed;\n width: fit-content;\n height: fit-content;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n background-color: white;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400; }\n .igv-ui-dialog .igv-ui-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee; }\n .igv-ui-dialog .igv-ui-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F; }\n .igv-ui-dialog .igv-ui-dialog-header div:hover {\n cursor: pointer;\n color: #444; }\n .igv-ui-dialog .igv-ui-dialog-one-liner {\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin: 8px;\n overflow-wrap: break-word;\n background-color: white;\n font-weight: bold; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel {\n width: 100%;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div {\n margin: 16px;\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child {\n background-color: #5ea4e0; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child {\n background-color: #c4c4c4; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f; }\n .igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f; }\n .igv-ui-dialog .igv-ui-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center; }\n .igv-ui-dialog .igv-ui-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF; }\n .igv-ui-dialog .igv-ui-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f; }\n\n.igv-ui-panel, .igv-ui-panel-column, .igv-ui-panel-row {\n z-index: 2048;\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n.igv-ui-panel-column {\n display: flex;\n flex-direction: column; }\n\n.igv-ui-panel-row {\n display: flex;\n flex-direction: row; }\n\n.igv-ui-textbox {\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start; }\n\n/*# sourceMappingURL=igv-ui.css.map */\n';
|
|
19389
19389
|
var style = document.createElement('style');
|
|
19390
19390
|
style.setAttribute('type', 'text/css');
|
|
19391
19391
|
style.innerHTML = css;
|
|
@@ -19911,7 +19911,7 @@
|
|
|
19911
19911
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19912
19912
|
* THE SOFTWARE.
|
|
19913
19913
|
*/
|
|
19914
|
-
const knownFileExtensions = new Set(["narrowpeak", "broadpeak", "regionpeak", "peaks", "bedgraph", "wig", "gff3", "gff", "gtf", "fusionjuncspan", "refflat", "seg", "aed", "bed", "vcf", "bb", "bigbed", "bw", "bigwig", "bam", "tdf", "refgene", "genepred", "genepredext", "bedpe", "bp", "snp", "rmsk", "cram", "gwas", "maf", "mut"]);
|
|
19914
|
+
const knownFileExtensions = new Set(["narrowpeak", "broadpeak", "regionpeak", "peaks", "bedgraph", "wig", "gff3", "gff", "gtf", "fusionjuncspan", "refflat", "seg", "aed", "bed", "vcf", "bb", "bigbed", "biginteract", "bw", "bigwig", "bam", "tdf", "refgene", "genepred", "genepredext", "bedpe", "bp", "snp", "rmsk", "cram", "gwas", "maf", "mut"]);
|
|
19915
19915
|
/**
|
|
19916
19916
|
* Return a custom format object with the given name.
|
|
19917
19917
|
* @param name
|
|
@@ -20032,6 +20032,7 @@
|
|
|
20032
20032
|
|
|
20033
20033
|
case "bedpe":
|
|
20034
20034
|
case "bedpe-loop":
|
|
20035
|
+
case "biginteract":
|
|
20035
20036
|
return "interact";
|
|
20036
20037
|
|
|
20037
20038
|
case "bp":
|
|
@@ -20286,6 +20287,30 @@
|
|
|
20286
20287
|
return window.location.protocol === "https:" || window.location.hostname === "localhost";
|
|
20287
20288
|
}
|
|
20288
20289
|
|
|
20290
|
+
const pairs = [['A', 'T'], ['G', 'C'], ['Y', 'R'], ['W', 'S'], ['K', 'M'], ['D', 'H'], ['B', 'V']];
|
|
20291
|
+
const complements = new Map();
|
|
20292
|
+
|
|
20293
|
+
for (let p of pairs) {
|
|
20294
|
+
const p1 = p[0];
|
|
20295
|
+
const p2 = p[1];
|
|
20296
|
+
complements.set(p1, p2);
|
|
20297
|
+
complements.set(p2, p1);
|
|
20298
|
+
complements.set(p1.toLowerCase(), p2.toLowerCase());
|
|
20299
|
+
complements.set(p2.toLowerCase(), p1.toLowerCase());
|
|
20300
|
+
}
|
|
20301
|
+
|
|
20302
|
+
function reverseComplementSequence(sequence) {
|
|
20303
|
+
let comp = '';
|
|
20304
|
+
let idx = sequence.length;
|
|
20305
|
+
|
|
20306
|
+
while (idx-- > 0) {
|
|
20307
|
+
const base = sequence[idx];
|
|
20308
|
+
comp += complements.has(base) ? complements.get(base) : base;
|
|
20309
|
+
}
|
|
20310
|
+
|
|
20311
|
+
return comp;
|
|
20312
|
+
}
|
|
20313
|
+
|
|
20289
20314
|
/*
|
|
20290
20315
|
* The MIT License (MIT)
|
|
20291
20316
|
*
|
|
@@ -20439,16 +20464,21 @@
|
|
|
20439
20464
|
const viewport = clickState.viewport;
|
|
20440
20465
|
|
|
20441
20466
|
if (viewport.referenceFrame.bpPerPixel <= 1) {
|
|
20467
|
+
const pixelWidth = viewport.getWidth();
|
|
20468
|
+
const bpWindow = pixelWidth * viewport.referenceFrame.bpPerPixel;
|
|
20469
|
+
const chr = viewport.referenceFrame.chr;
|
|
20470
|
+
const start = Math.floor(viewport.referenceFrame.start);
|
|
20471
|
+
const end = Math.ceil(start + bpWindow);
|
|
20442
20472
|
const items = [{
|
|
20443
|
-
label: 'View visible sequence...',
|
|
20473
|
+
label: this.reversed ? 'View visible sequence (reversed)...' : 'View visible sequence...',
|
|
20444
20474
|
click: async () => {
|
|
20445
|
-
|
|
20446
|
-
|
|
20447
|
-
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20451
|
-
Alert.presentAlert(
|
|
20475
|
+
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
20476
|
+
|
|
20477
|
+
if (this.reversed) {
|
|
20478
|
+
seq = reverseComplementSequence(seq);
|
|
20479
|
+
}
|
|
20480
|
+
|
|
20481
|
+
Alert.presentAlert(seq);
|
|
20452
20482
|
}
|
|
20453
20483
|
}];
|
|
20454
20484
|
|
|
@@ -20456,13 +20486,18 @@
|
|
|
20456
20486
|
items.push({
|
|
20457
20487
|
label: 'Copy visible sequence',
|
|
20458
20488
|
click: async () => {
|
|
20459
|
-
|
|
20460
|
-
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
|
|
20464
|
-
|
|
20465
|
-
|
|
20489
|
+
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
20490
|
+
|
|
20491
|
+
if (this.reversed) {
|
|
20492
|
+
seq = reverseComplementSequence(seq);
|
|
20493
|
+
}
|
|
20494
|
+
|
|
20495
|
+
try {
|
|
20496
|
+
await navigator.clipboard.writeText(seq);
|
|
20497
|
+
} catch (e) {
|
|
20498
|
+
console.error(e);
|
|
20499
|
+
Alert.presentAlert(`error copying sequence to clipboard ${e}`);
|
|
20500
|
+
}
|
|
20466
20501
|
}
|
|
20467
20502
|
});
|
|
20468
20503
|
}
|
|
@@ -20603,7 +20638,7 @@
|
|
|
20603
20638
|
}
|
|
20604
20639
|
}
|
|
20605
20640
|
|
|
20606
|
-
supportsWholeGenome() {
|
|
20641
|
+
get supportsWholeGenome() {
|
|
20607
20642
|
return false;
|
|
20608
20643
|
}
|
|
20609
20644
|
|
|
@@ -20671,12 +20706,13 @@
|
|
|
20671
20706
|
});
|
|
20672
20707
|
this.$viewport.append(this.$content);
|
|
20673
20708
|
this.$content.height(this.$viewport.height());
|
|
20674
|
-
this.contentDiv = this.$content.get(0);
|
|
20675
|
-
this.$
|
|
20676
|
-
|
|
20677
|
-
this.canvas = this.$canvas.get(0)
|
|
20678
|
-
this.ctx = this.canvas.getContext("2d")
|
|
20679
|
-
|
|
20709
|
+
this.contentDiv = this.$content.get(0); // this.$canvas = $('<canvas>')
|
|
20710
|
+
// this.$content.append(this.$canvas)
|
|
20711
|
+
//
|
|
20712
|
+
// this.canvas = this.$canvas.get(0)
|
|
20713
|
+
// this.ctx = this.canvas.getContext("2d")
|
|
20714
|
+
|
|
20715
|
+
this.$viewport.width(width);
|
|
20680
20716
|
this.initializationHelper();
|
|
20681
20717
|
}
|
|
20682
20718
|
|
|
@@ -20732,14 +20768,13 @@
|
|
|
20732
20768
|
console.log('Viewport - draw(drawConfiguration, features, roiFeatures)');
|
|
20733
20769
|
}
|
|
20734
20770
|
|
|
20735
|
-
checkContentHeight() {
|
|
20771
|
+
checkContentHeight(features) {
|
|
20736
20772
|
let track = this.trackView.track;
|
|
20773
|
+
features = features || this.cachedFeatures;
|
|
20737
20774
|
|
|
20738
20775
|
if ("FILL" === track.displayMode) {
|
|
20739
20776
|
this.setContentHeight(this.$viewport.height());
|
|
20740
20777
|
} else if (typeof track.computePixelHeight === 'function') {
|
|
20741
|
-
let features = this.cachedFeatures;
|
|
20742
|
-
|
|
20743
20778
|
if (features && features.length > 0) {
|
|
20744
20779
|
let requiredContentHeight = track.computePixelHeight(features);
|
|
20745
20780
|
let currentContentHeight = this.$content.height();
|
|
@@ -20759,7 +20794,6 @@
|
|
|
20759
20794
|
// Maximum height of a canvas is ~32,000 pixels on Chrome, possibly smaller on other platforms
|
|
20760
20795
|
contentHeight = Math.min(contentHeight, 32000);
|
|
20761
20796
|
this.$content.height(contentHeight);
|
|
20762
|
-
if (this.tile) this.tile.invalidate = true;
|
|
20763
20797
|
}
|
|
20764
20798
|
|
|
20765
20799
|
isLoading() {
|
|
@@ -20774,8 +20808,6 @@
|
|
|
20774
20808
|
|
|
20775
20809
|
setWidth(width) {
|
|
20776
20810
|
this.$viewport.width(width);
|
|
20777
|
-
this.canvas.style.width = `${width}px`;
|
|
20778
|
-
this.canvas.setAttribute('width', width);
|
|
20779
20811
|
}
|
|
20780
20812
|
|
|
20781
20813
|
getWidth() {
|
|
@@ -20803,7 +20835,6 @@
|
|
|
20803
20835
|
this.popover.dispose();
|
|
20804
20836
|
}
|
|
20805
20837
|
|
|
20806
|
-
this.removeMouseHandlers();
|
|
20807
20838
|
this.$viewport.get(0).remove(); // Null out all properties -- this should not be neccessary, but just in case there is a
|
|
20808
20839
|
// reference to self somewhere we want to free memory.
|
|
20809
20840
|
|
|
@@ -23060,7 +23091,7 @@
|
|
|
23060
23091
|
}
|
|
23061
23092
|
};
|
|
23062
23093
|
|
|
23063
|
-
const _version = "2.
|
|
23094
|
+
const _version = "2.12.0";
|
|
23064
23095
|
|
|
23065
23096
|
function version$1() {
|
|
23066
23097
|
return _version;
|
|
@@ -23410,6 +23441,7 @@
|
|
|
23410
23441
|
}
|
|
23411
23442
|
|
|
23412
23443
|
async getSequence(chr, start, end) {
|
|
23444
|
+
chr = this.getChromosomeName(chr);
|
|
23413
23445
|
return this.sequence.getSequence(chr, start, end);
|
|
23414
23446
|
}
|
|
23415
23447
|
|
|
@@ -23536,15 +23568,13 @@
|
|
|
23536
23568
|
});
|
|
23537
23569
|
this.$viewport.append(this.$spinner);
|
|
23538
23570
|
this.$spinner.append($$1('<div>'));
|
|
23539
|
-
const
|
|
23540
|
-
track
|
|
23541
|
-
} = this.trackView;
|
|
23571
|
+
const track = this.trackView.track;
|
|
23542
23572
|
|
|
23543
23573
|
if ('sequence' !== track.type) {
|
|
23544
23574
|
this.$zoomInNotice = this.createZoomInNotice(this.$content);
|
|
23545
23575
|
}
|
|
23546
23576
|
|
|
23547
|
-
if (track.name && "sequence" !== track.
|
|
23577
|
+
if (track.name && "sequence" !== track.id) {
|
|
23548
23578
|
this.$trackLabel = $$1('<div class="igv-track-label">');
|
|
23549
23579
|
this.$viewport.append(this.$trackLabel);
|
|
23550
23580
|
this.setTrackLabel(track.name);
|
|
@@ -23558,6 +23588,11 @@
|
|
|
23558
23588
|
this.addMouseHandlers();
|
|
23559
23589
|
}
|
|
23560
23590
|
|
|
23591
|
+
setContentHeight(contentHeight) {
|
|
23592
|
+
super.setContentHeight(contentHeight);
|
|
23593
|
+
if (this.featureCache) this.featureCache.redraw = true;
|
|
23594
|
+
}
|
|
23595
|
+
|
|
23561
23596
|
setTrackLabel(label) {
|
|
23562
23597
|
this.$trackLabel.empty();
|
|
23563
23598
|
this.$trackLabel.html(label);
|
|
@@ -23574,55 +23609,72 @@
|
|
|
23574
23609
|
this.$spinner.hide();
|
|
23575
23610
|
}
|
|
23576
23611
|
}
|
|
23612
|
+
/**
|
|
23613
|
+
* Test to determine if we are zoomed in far enough to see features. Applicable to tracks with visibility windows.
|
|
23614
|
+
*
|
|
23615
|
+
* As a side effect the viewports canvas is removed if zoomed out.
|
|
23616
|
+
*
|
|
23617
|
+
* @returns {boolean} true if we are zoomed in past visibility window, false otherwise
|
|
23618
|
+
*/
|
|
23577
23619
|
|
|
23578
|
-
checkZoomIn() {
|
|
23579
|
-
const showZoomInNotice = () => {
|
|
23580
|
-
const referenceFrame = this.referenceFrame;
|
|
23581
23620
|
|
|
23582
|
-
|
|
23621
|
+
checkZoomIn() {
|
|
23622
|
+
const zoomedOutOfWindow = () => {
|
|
23623
|
+
if (this.referenceFrame.chr.toLowerCase() === "all" && !this.trackView.track.supportsWholeGenome) {
|
|
23583
23624
|
return true;
|
|
23584
23625
|
} else {
|
|
23585
23626
|
const visibilityWindow = this.trackView.track.visibilityWindow;
|
|
23586
|
-
return visibilityWindow !== undefined && visibilityWindow > 0 && referenceFrame.bpPerPixel * this.$viewport.width() > visibilityWindow;
|
|
23627
|
+
return visibilityWindow !== undefined && visibilityWindow > 0 && this.referenceFrame.bpPerPixel * this.$viewport.width() > visibilityWindow;
|
|
23587
23628
|
}
|
|
23588
23629
|
};
|
|
23589
23630
|
|
|
23631
|
+
if (this.trackView.track && "sequence" === this.trackView.track.type && this.referenceFrame.bpPerPixel > 1) {
|
|
23632
|
+
$$1(this.canvas).remove();
|
|
23633
|
+
this.canvas = undefined; //this.featureCache = undefined
|
|
23634
|
+
|
|
23635
|
+
return false;
|
|
23636
|
+
}
|
|
23637
|
+
|
|
23590
23638
|
if (!this.viewIsReady()) {
|
|
23591
23639
|
return false;
|
|
23592
23640
|
}
|
|
23593
23641
|
|
|
23594
|
-
if (
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
|
|
23598
|
-
|
|
23599
|
-
|
|
23600
|
-
}
|
|
23642
|
+
if (zoomedOutOfWindow()) {
|
|
23643
|
+
// Out of visibility window
|
|
23644
|
+
if (this.canvas) {
|
|
23645
|
+
$$1(this.canvas).remove();
|
|
23646
|
+
this.canvas = undefined; //this.featureCache = undefined
|
|
23647
|
+
}
|
|
23601
23648
|
|
|
23602
|
-
|
|
23649
|
+
if (this.trackView.track.autoHeight) {
|
|
23650
|
+
const minHeight = this.trackView.minHeight || 0;
|
|
23651
|
+
this.setContentHeight(minHeight);
|
|
23652
|
+
}
|
|
23603
23653
|
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
|
|
23607
|
-
}
|
|
23654
|
+
if (this.$zoomInNotice) {
|
|
23655
|
+
this.$zoomInNotice.show();
|
|
23656
|
+
}
|
|
23608
23657
|
|
|
23609
|
-
|
|
23610
|
-
|
|
23658
|
+
return false;
|
|
23659
|
+
} else {
|
|
23660
|
+
if (this.$zoomInNotice) {
|
|
23611
23661
|
this.$zoomInNotice.hide();
|
|
23612
|
-
return true;
|
|
23613
23662
|
}
|
|
23614
|
-
}
|
|
23615
23663
|
|
|
23616
|
-
|
|
23664
|
+
return true;
|
|
23665
|
+
}
|
|
23617
23666
|
}
|
|
23667
|
+
/**
|
|
23668
|
+
* Adjust the canvas to the current genomic state.
|
|
23669
|
+
*/
|
|
23670
|
+
|
|
23618
23671
|
|
|
23619
23672
|
shift() {
|
|
23620
|
-
const
|
|
23621
|
-
const referenceFrame = self.referenceFrame;
|
|
23673
|
+
const referenceFrame = this.referenceFrame;
|
|
23622
23674
|
|
|
23623
|
-
if (
|
|
23624
|
-
const pixelOffset = Math.round((
|
|
23625
|
-
|
|
23675
|
+
if (this.canvas && this.canvas._data && this.canvas._data.chr === this.referenceFrame.chr && this.canvas._data.bpPerPixel === referenceFrame.bpPerPixel) {
|
|
23676
|
+
const pixelOffset = Math.round((this.canvas._data.startBP - referenceFrame.start) / referenceFrame.bpPerPixel);
|
|
23677
|
+
this.canvas.style.left = pixelOffset + "px";
|
|
23626
23678
|
}
|
|
23627
23679
|
}
|
|
23628
23680
|
|
|
@@ -23648,9 +23700,10 @@
|
|
|
23648
23700
|
this.startSpinner();
|
|
23649
23701
|
|
|
23650
23702
|
try {
|
|
23651
|
-
const
|
|
23703
|
+
const track = this.trackView.track;
|
|
23704
|
+
const features = await this.getFeatures(track, chr, bpStart, bpEnd, referenceFrame.bpPerPixel);
|
|
23652
23705
|
let roiFeatures = [];
|
|
23653
|
-
const roi = mergeArrays(this.browser.roi,
|
|
23706
|
+
const roi = mergeArrays(this.browser.roi, track.roi);
|
|
23654
23707
|
|
|
23655
23708
|
if (roi) {
|
|
23656
23709
|
for (let r of roi) {
|
|
@@ -23662,11 +23715,13 @@
|
|
|
23662
23715
|
}
|
|
23663
23716
|
}
|
|
23664
23717
|
|
|
23665
|
-
|
|
23718
|
+
const mr = track && ("wig" === track.type || "merged" === track.type); // wig tracks are potentially multiresolution (e.g. bigwig)
|
|
23719
|
+
|
|
23720
|
+
this.featureCache = new FeatureCache(chr, bpStart, bpEnd, referenceFrame.bpPerPixel, features, roiFeatures, mr);
|
|
23666
23721
|
this.loading = false;
|
|
23667
23722
|
this.hideMessage();
|
|
23668
23723
|
this.stopSpinner();
|
|
23669
|
-
return this.
|
|
23724
|
+
return this.featureCache;
|
|
23670
23725
|
} catch (error) {
|
|
23671
23726
|
// Track might have been removed during load
|
|
23672
23727
|
if (this.trackView && this.trackView.disposed !== true) {
|
|
@@ -23679,38 +23734,32 @@
|
|
|
23679
23734
|
this.stopSpinner();
|
|
23680
23735
|
}
|
|
23681
23736
|
}
|
|
23737
|
+
/**
|
|
23738
|
+
* Repaint the canvas using the cached features
|
|
23739
|
+
*
|
|
23740
|
+
*/
|
|
23682
23741
|
|
|
23683
|
-
|
|
23684
|
-
|
|
23742
|
+
|
|
23743
|
+
repaint() {
|
|
23744
|
+
if (undefined === this.featureCache) {
|
|
23685
23745
|
return;
|
|
23686
23746
|
}
|
|
23687
23747
|
|
|
23688
23748
|
let {
|
|
23689
23749
|
features,
|
|
23690
|
-
roiFeatures
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
endBP
|
|
23694
|
-
} = this.tile; // const isWGV = GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr)
|
|
23695
|
-
|
|
23696
|
-
const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
|
|
23697
|
-
let pixelWidth;
|
|
23698
|
-
|
|
23699
|
-
if (isWGV) {
|
|
23700
|
-
bpPerPixel = this.referenceFrame.end / this.$viewport.width();
|
|
23701
|
-
startBP = 0;
|
|
23702
|
-
endBP = this.referenceFrame.end;
|
|
23703
|
-
pixelWidth = this.$viewport.width();
|
|
23704
|
-
} else {
|
|
23705
|
-
pixelWidth = Math.ceil((endBP - startBP) / bpPerPixel);
|
|
23706
|
-
} // For deep tracks we paint a canvas == 3*viewportHeight centered on the current vertical scroll position
|
|
23750
|
+
roiFeatures
|
|
23751
|
+
} = this.featureCache; //this.tile.bpPerPixel = this.referenceFrame.bpPerPixel
|
|
23752
|
+
// const isWGV = GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr)
|
|
23707
23753
|
|
|
23754
|
+
const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr); // Canvas dimensions. There is no left-right panning for WGV so canvas width is viewport width.
|
|
23755
|
+
// For deep tracks we paint a canvas == 3*viewportHeight centered on the current vertical scroll position
|
|
23708
23756
|
|
|
23757
|
+
const pixelWidth = isWGV ? this.$viewport.width() : 3 * this.$viewport.width();
|
|
23709
23758
|
const viewportHeight = this.$viewport.height();
|
|
23710
23759
|
const contentHeight = this.getContentHeight();
|
|
23711
23760
|
const minHeight = roiFeatures ? Math.max(contentHeight, viewportHeight) : contentHeight; // Need to fill viewport for ROIs.
|
|
23712
23761
|
|
|
23713
|
-
|
|
23762
|
+
const pixelHeight = Math.min(minHeight, 3 * viewportHeight);
|
|
23714
23763
|
|
|
23715
23764
|
if (0 === pixelWidth || 0 === pixelHeight) {
|
|
23716
23765
|
if (this.canvas) {
|
|
@@ -23720,26 +23769,22 @@
|
|
|
23720
23769
|
return;
|
|
23721
23770
|
}
|
|
23722
23771
|
|
|
23723
|
-
const canvasTop = Math.max(0, -this.$content.position().top - viewportHeight);
|
|
23724
|
-
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
devicePixelRatio = window.devicePixelRatio;
|
|
23729
|
-
} else {
|
|
23730
|
-
devicePixelRatio = this.trackView.track.supportHiDPI === false ? 1 : window.devicePixelRatio;
|
|
23731
|
-
}
|
|
23732
|
-
|
|
23733
|
-
const pixelXOffset = Math.round((startBP - this.referenceFrame.start) / this.referenceFrame.bpPerPixel);
|
|
23772
|
+
const canvasTop = Math.max(0, -this.$content.position().top - viewportHeight);
|
|
23773
|
+
const bpPerPixel = this.referenceFrame.bpPerPixel;
|
|
23774
|
+
const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
|
|
23775
|
+
const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
|
|
23776
|
+
const pixelXOffset = Math.round((startBP - this.referenceFrame.start) / bpPerPixel);
|
|
23734
23777
|
const newCanvas = $$1('<canvas class="igv-canvas">').get(0);
|
|
23735
|
-
const ctx = newCanvas.getContext("2d");
|
|
23736
23778
|
newCanvas.style.width = pixelWidth + "px";
|
|
23737
23779
|
newCanvas.style.height = pixelHeight + "px";
|
|
23780
|
+
newCanvas.style.left = pixelXOffset + "px";
|
|
23781
|
+
newCanvas.style.top = canvasTop + "px"; // Always use high DPI if in "FILL" display mode, otherwise use track setting;
|
|
23782
|
+
|
|
23783
|
+
const devicePixelRatio = "FILL" === this.trackView.track.displayMode || this.trackView.track.supportHiDPI !== false ? window.devicePixelRatio : 1;
|
|
23738
23784
|
newCanvas.width = devicePixelRatio * pixelWidth;
|
|
23739
23785
|
newCanvas.height = devicePixelRatio * pixelHeight;
|
|
23786
|
+
const ctx = newCanvas.getContext("2d");
|
|
23740
23787
|
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
23741
|
-
newCanvas.style.left = pixelXOffset + "px";
|
|
23742
|
-
newCanvas.style.top = canvasTop + "px";
|
|
23743
23788
|
ctx.translate(0, -canvasTop);
|
|
23744
23789
|
const drawConfiguration = {
|
|
23745
23790
|
context: ctx,
|
|
@@ -23756,20 +23801,32 @@
|
|
|
23756
23801
|
viewportWidth: this.$viewport.width()
|
|
23757
23802
|
};
|
|
23758
23803
|
this.draw(drawConfiguration, features, roiFeatures);
|
|
23759
|
-
this.
|
|
23760
|
-
|
|
23761
|
-
bottom: canvasTop + pixelHeight
|
|
23762
|
-
};
|
|
23804
|
+
this.featureCache.canvasTop = canvasTop;
|
|
23805
|
+
this.featureCache.height = pixelHeight;
|
|
23763
23806
|
|
|
23764
|
-
if (this
|
|
23765
|
-
this
|
|
23807
|
+
if (this.canvas) {
|
|
23808
|
+
$$1(this.canvas).remove();
|
|
23766
23809
|
}
|
|
23767
23810
|
|
|
23768
|
-
|
|
23769
|
-
|
|
23811
|
+
newCanvas._data = {
|
|
23812
|
+
chr: this.featureCache.chr,
|
|
23813
|
+
bpPerPixel,
|
|
23814
|
+
startBP,
|
|
23815
|
+
endBP,
|
|
23816
|
+
pixelHeight,
|
|
23817
|
+
pixelTop: canvasTop
|
|
23818
|
+
};
|
|
23770
23819
|
this.canvas = newCanvas;
|
|
23771
|
-
this.
|
|
23820
|
+
this.$content.append($$1(newCanvas));
|
|
23772
23821
|
}
|
|
23822
|
+
/**
|
|
23823
|
+
* Draw the associated track.
|
|
23824
|
+
*
|
|
23825
|
+
* @param drawConfiguration
|
|
23826
|
+
* @param features
|
|
23827
|
+
* @param roiFeatures
|
|
23828
|
+
*/
|
|
23829
|
+
|
|
23773
23830
|
|
|
23774
23831
|
draw(drawConfiguration, features, roiFeatures) {
|
|
23775
23832
|
// console.log(`${ Date.now() } viewport draw(). track ${ this.trackView.track.type }. content-css-top ${ this.$content.css('top') }. canvas-top ${ drawConfiguration.pixelTop }.`)
|
|
@@ -23784,51 +23841,6 @@
|
|
|
23784
23841
|
r.track.draw(drawConfiguration);
|
|
23785
23842
|
}
|
|
23786
23843
|
}
|
|
23787
|
-
} // TODO: Nolonger used. Will discard
|
|
23788
|
-
|
|
23789
|
-
|
|
23790
|
-
async toSVG(tile) {
|
|
23791
|
-
// Nothing to do if zoomInNotice is active
|
|
23792
|
-
if (this.$zoomInNotice && this.$zoomInNotice.is(":visible")) {
|
|
23793
|
-
return;
|
|
23794
|
-
}
|
|
23795
|
-
|
|
23796
|
-
const referenceFrame = this.referenceFrame;
|
|
23797
|
-
const bpPerPixel = tile.bpPerPixel;
|
|
23798
|
-
const features = tile.features;
|
|
23799
|
-
const roiFeatures = tile.roiFeatures;
|
|
23800
|
-
const pixelWidth = this.$viewport.width();
|
|
23801
|
-
const pixelHeight = this.$viewport.height();
|
|
23802
|
-
const bpStart = referenceFrame.start;
|
|
23803
|
-
const bpEnd = referenceFrame.start + pixelWidth * referenceFrame.bpPerPixel;
|
|
23804
|
-
const ctx$1 = new ctx({
|
|
23805
|
-
// svg
|
|
23806
|
-
width: pixelWidth,
|
|
23807
|
-
height: pixelHeight,
|
|
23808
|
-
viewbox: {
|
|
23809
|
-
x: 0,
|
|
23810
|
-
y: -this.$content.position().top,
|
|
23811
|
-
width: pixelWidth,
|
|
23812
|
-
height: pixelHeight
|
|
23813
|
-
}
|
|
23814
|
-
});
|
|
23815
|
-
const drawConfiguration = {
|
|
23816
|
-
viewport: this,
|
|
23817
|
-
context: ctx$1,
|
|
23818
|
-
top: -this.$content.position().top,
|
|
23819
|
-
pixelTop: 0,
|
|
23820
|
-
// for compatibility with canvas draw
|
|
23821
|
-
pixelWidth,
|
|
23822
|
-
pixelHeight,
|
|
23823
|
-
bpStart,
|
|
23824
|
-
bpEnd,
|
|
23825
|
-
bpPerPixel,
|
|
23826
|
-
referenceFrame: this.referenceFrame,
|
|
23827
|
-
selection: this.selection,
|
|
23828
|
-
viewportWidth: pixelWidth
|
|
23829
|
-
};
|
|
23830
|
-
this.draw(drawConfiguration, features, roiFeatures);
|
|
23831
|
-
return ctx$1.getSerializedSvg(true);
|
|
23832
23844
|
}
|
|
23833
23845
|
|
|
23834
23846
|
containsPosition(chr, position) {
|
|
@@ -23843,15 +23855,17 @@
|
|
|
23843
23855
|
return this.loading;
|
|
23844
23856
|
}
|
|
23845
23857
|
|
|
23846
|
-
|
|
23847
|
-
if (!this.
|
|
23848
|
-
const
|
|
23858
|
+
savePNG() {
|
|
23859
|
+
if (!this.canvas) return;
|
|
23860
|
+
const canvasMetadata = this.featureCache;
|
|
23861
|
+
const canvasTop = canvasMetadata ? canvasMetadata.canvasTop : 0;
|
|
23849
23862
|
const devicePixelRatio = window.devicePixelRatio;
|
|
23850
23863
|
const w = this.$viewport.width() * devicePixelRatio;
|
|
23851
23864
|
const h = this.$viewport.height() * devicePixelRatio;
|
|
23852
23865
|
const x = -$$1(this.canvas).position().left * devicePixelRatio;
|
|
23853
23866
|
const y = (-this.$content.position().top - canvasTop) * devicePixelRatio;
|
|
23854
|
-
const
|
|
23867
|
+
const ctx = this.canvas.getContext("2d");
|
|
23868
|
+
const imageData = ctx.getImageData(x, y, w, h);
|
|
23855
23869
|
const exportCanvas = document.createElement('canvas');
|
|
23856
23870
|
const exportCtx = exportCanvas.getContext('2d');
|
|
23857
23871
|
exportCanvas.width = imageData.width;
|
|
@@ -23967,29 +23981,44 @@
|
|
|
23967
23981
|
viewportWidth: width,
|
|
23968
23982
|
selection: this.selection
|
|
23969
23983
|
};
|
|
23970
|
-
const features = this.
|
|
23971
|
-
const roiFeatures = this.
|
|
23984
|
+
const features = this.featureCache ? this.featureCache.features : [];
|
|
23985
|
+
const roiFeatures = this.featureCache ? this.featureCache.roiFeatures : undefined;
|
|
23972
23986
|
this.draw(config, features, roiFeatures);
|
|
23973
23987
|
context.restore();
|
|
23974
23988
|
}
|
|
23975
23989
|
|
|
23976
|
-
|
|
23977
|
-
return this.
|
|
23990
|
+
get cachedFeatures() {
|
|
23991
|
+
return this.featureCache ? this.featureCache.features : [];
|
|
23978
23992
|
}
|
|
23979
23993
|
|
|
23980
23994
|
async getFeatures(track, chr, start, end, bpPerPixel) {
|
|
23981
|
-
if (this.
|
|
23982
|
-
return this.
|
|
23995
|
+
if (this.featureCache && this.featureCache.containsRange(chr, start, end, bpPerPixel)) {
|
|
23996
|
+
return this.featureCache.features;
|
|
23983
23997
|
} else if (typeof track.getFeatures === "function") {
|
|
23984
23998
|
const features = await track.getFeatures(chr, start, end, bpPerPixel, this);
|
|
23985
|
-
this.
|
|
23986
|
-
this.checkContentHeight();
|
|
23999
|
+
this.checkContentHeight(features);
|
|
23987
24000
|
return features;
|
|
23988
24001
|
} else {
|
|
23989
24002
|
return undefined;
|
|
23990
24003
|
}
|
|
23991
24004
|
}
|
|
23992
24005
|
|
|
24006
|
+
needsRepaint() {
|
|
24007
|
+
if (!this.canvas) return true;
|
|
24008
|
+
const data = this.canvas._data;
|
|
24009
|
+
return !data || this.referenceFrame.start < data.startBP || this.referenceFrame.end > data.endBP || this.referenceFrame.chr !== data.chr || this.referenceFrame.bpPerPixel != data.bpPerPixel;
|
|
24010
|
+
}
|
|
24011
|
+
|
|
24012
|
+
needsReload() {
|
|
24013
|
+
if (!this.featureCache) return true;
|
|
24014
|
+
const referenceFrame = this.referenceFrame;
|
|
24015
|
+
const chr = this.referenceFrame.chr;
|
|
24016
|
+
const start = referenceFrame.start;
|
|
24017
|
+
const end = start + referenceFrame.toBP($$1(this.contentDiv).width());
|
|
24018
|
+
const bpPerPixel = referenceFrame.bpPerPixel;
|
|
24019
|
+
return !this.featureCache.containsRange(chr, start, end, bpPerPixel);
|
|
24020
|
+
}
|
|
24021
|
+
|
|
23993
24022
|
createZoomInNotice($parent) {
|
|
23994
24023
|
const $container = $$1('<div>', {
|
|
23995
24024
|
class: 'igv-zoom-in-notice-container'
|
|
@@ -24007,36 +24036,42 @@
|
|
|
24007
24036
|
}
|
|
24008
24037
|
|
|
24009
24038
|
addMouseHandlers() {
|
|
24010
|
-
this
|
|
24011
|
-
this.
|
|
24012
|
-
this.addViewportTouchStartHandler(this.$viewport.get(0));
|
|
24013
|
-
this.addViewportMouseUpHandler(this.$viewport.get(0));
|
|
24014
|
-
this.addViewportTouchEndHandler(this.$viewport.get(0));
|
|
24015
|
-
this.addViewportClickHandler(this.$viewport.get(0));
|
|
24039
|
+
const viewport = this.$viewport.get(0);
|
|
24040
|
+
this.addViewportContextMenuHandler(viewport);
|
|
24016
24041
|
|
|
24017
|
-
|
|
24018
|
-
this.
|
|
24019
|
-
|
|
24020
|
-
|
|
24042
|
+
const md = event => {
|
|
24043
|
+
this.enableClick = true;
|
|
24044
|
+
this.browser.mouseDownOnViewport(event, this);
|
|
24045
|
+
pageCoordinates$1(event);
|
|
24046
|
+
};
|
|
24021
24047
|
|
|
24022
|
-
|
|
24023
|
-
|
|
24024
|
-
|
|
24025
|
-
|
|
24026
|
-
|
|
24027
|
-
|
|
24028
|
-
|
|
24048
|
+
viewport.addEventListener('mousedown', md);
|
|
24049
|
+
viewport.addEventListener('touchstart', md);
|
|
24050
|
+
|
|
24051
|
+
const mu = event => {
|
|
24052
|
+
// Any mouse up cancels drag and scrolling
|
|
24053
|
+
if (this.browser.dragObject || this.browser.isScrolling) {
|
|
24054
|
+
this.browser.cancelTrackPan(); // event.preventDefault();
|
|
24055
|
+
// event.stopPropagation();
|
|
24056
|
+
|
|
24057
|
+
this.enableClick = false; // Until next mouse down
|
|
24058
|
+
} else {
|
|
24059
|
+
this.browser.cancelTrackPan();
|
|
24060
|
+
this.browser.endTrackDrag();
|
|
24061
|
+
}
|
|
24062
|
+
};
|
|
24063
|
+
|
|
24064
|
+
viewport.addEventListener('mouseup', mu);
|
|
24065
|
+
viewport.addEventListener('touchend', mu);
|
|
24066
|
+
this.addViewportClickHandler(this.$viewport.get(0));
|
|
24029
24067
|
|
|
24030
24068
|
if (this.trackView.track.name && "sequence" !== this.trackView.track.config.type) {
|
|
24031
|
-
this.
|
|
24069
|
+
this.addTrackLabelClickHandler(this.$trackLabel.get(0));
|
|
24032
24070
|
}
|
|
24033
24071
|
}
|
|
24034
24072
|
|
|
24035
24073
|
addViewportContextMenuHandler(viewport) {
|
|
24036
|
-
|
|
24037
|
-
viewport.addEventListener('contextmenu', this.boundContextMenuHandler);
|
|
24038
|
-
|
|
24039
|
-
function contextMenuHandler(event) {
|
|
24074
|
+
viewport.addEventListener('contextmenu', event => {
|
|
24040
24075
|
// Ignore if we are doing a drag. This can happen with touch events.
|
|
24041
24076
|
if (this.browser.dragObject) {
|
|
24042
24077
|
return false;
|
|
@@ -24076,54 +24111,11 @@
|
|
|
24076
24111
|
click: () => this.saveSVG()
|
|
24077
24112
|
});
|
|
24078
24113
|
this.browser.menuPopup.presentTrackContextMenu(event, menuItems);
|
|
24079
|
-
}
|
|
24080
|
-
}
|
|
24081
|
-
|
|
24082
|
-
removeViewportContextMenuHandler(viewport) {
|
|
24083
|
-
viewport.removeEventListener('contextmenu', this.boundContextMenuHandler);
|
|
24084
|
-
}
|
|
24085
|
-
|
|
24086
|
-
addViewportMouseDownHandler(viewport) {
|
|
24087
|
-
this.boundMouseDownHandler = mouseDownHandler.bind(this);
|
|
24088
|
-
viewport.addEventListener('mousedown', this.boundMouseDownHandler);
|
|
24089
|
-
}
|
|
24090
|
-
|
|
24091
|
-
removeViewportMouseDownHandler(viewport) {
|
|
24092
|
-
viewport.removeEventListener('mousedown', this.boundMouseDownHandler);
|
|
24093
|
-
}
|
|
24094
|
-
|
|
24095
|
-
addViewportTouchStartHandler(viewport) {
|
|
24096
|
-
this.boundTouchStartHandler = mouseDownHandler.bind(this);
|
|
24097
|
-
viewport.addEventListener('touchstart', this.boundTouchStartHandler);
|
|
24098
|
-
}
|
|
24099
|
-
|
|
24100
|
-
removeViewportTouchStartHandler(viewport) {
|
|
24101
|
-
viewport.removeEventListener('touchstart', this.boundTouchStartHandler);
|
|
24102
|
-
}
|
|
24103
|
-
|
|
24104
|
-
addViewportMouseUpHandler(viewport) {
|
|
24105
|
-
this.boundMouseUpHandler = mouseUpHandler.bind(this);
|
|
24106
|
-
viewport.addEventListener('mouseup', this.boundMouseUpHandler);
|
|
24107
|
-
}
|
|
24108
|
-
|
|
24109
|
-
removeViewportMouseUpHandler(viewport) {
|
|
24110
|
-
viewport.removeEventListener('mouseup', this.boundMouseUpHandler);
|
|
24111
|
-
}
|
|
24112
|
-
|
|
24113
|
-
addViewportTouchEndHandler(viewport) {
|
|
24114
|
-
this.boundTouchEndHandler = mouseUpHandler.bind(this);
|
|
24115
|
-
viewport.addEventListener('touchend', this.boundTouchEndHandler);
|
|
24116
|
-
}
|
|
24117
|
-
|
|
24118
|
-
removeViewportTouchEndHandler(viewport) {
|
|
24119
|
-
viewport.removeEventListener('touchend', this.boundTouchEndHandler);
|
|
24114
|
+
});
|
|
24120
24115
|
}
|
|
24121
24116
|
|
|
24122
24117
|
addViewportClickHandler(viewport) {
|
|
24123
|
-
|
|
24124
|
-
viewport.addEventListener('click', this.boundClickHandler);
|
|
24125
|
-
|
|
24126
|
-
function clickHandler(event) {
|
|
24118
|
+
viewport.addEventListener('click', event => {
|
|
24127
24119
|
if (this.enableClick) {
|
|
24128
24120
|
if (3 === event.which || event.ctrlKey) {
|
|
24129
24121
|
return;
|
|
@@ -24198,18 +24190,11 @@
|
|
|
24198
24190
|
|
|
24199
24191
|
lastClickTime = time;
|
|
24200
24192
|
}
|
|
24201
|
-
}
|
|
24202
|
-
}
|
|
24203
|
-
|
|
24204
|
-
removeViewportClickHandler(viewport) {
|
|
24205
|
-
viewport.removeEventListener('click', this.boundClickHandler);
|
|
24193
|
+
});
|
|
24206
24194
|
}
|
|
24207
24195
|
|
|
24208
24196
|
addTrackLabelClickHandler(trackLabel) {
|
|
24209
|
-
|
|
24210
|
-
trackLabel.addEventListener('click', this.boundTrackLabelClickHandler);
|
|
24211
|
-
|
|
24212
|
-
function clickHandler(event) {
|
|
24197
|
+
trackLabel.addEventListener('click', event => {
|
|
24213
24198
|
event.stopPropagation();
|
|
24214
24199
|
const {
|
|
24215
24200
|
track
|
|
@@ -24230,44 +24215,16 @@
|
|
|
24230
24215
|
this.popover = new Popover(this.browser.columnContainer, track.name || '');
|
|
24231
24216
|
this.popover.presentContentWithEvent(event, str);
|
|
24232
24217
|
}
|
|
24233
|
-
}
|
|
24234
|
-
}
|
|
24235
|
-
|
|
24236
|
-
removeTrackLabelClickHandler(trackLabel) {
|
|
24237
|
-
trackLabel.removeEventListener('click', this.boundTrackLabelClickHandler);
|
|
24218
|
+
});
|
|
24238
24219
|
}
|
|
24239
24220
|
|
|
24240
24221
|
}
|
|
24241
24222
|
|
|
24242
|
-
function mouseDownHandler(event) {
|
|
24243
|
-
this.enableClick = true;
|
|
24244
|
-
this.browser.mouseDownOnViewport(event, this);
|
|
24245
|
-
pageCoordinates$1(event);
|
|
24246
|
-
}
|
|
24247
|
-
|
|
24248
|
-
function mouseUpHandler(event) {
|
|
24249
|
-
// Any mouse up cancels drag and scrolling
|
|
24250
|
-
if (this.browser.dragObject || this.browser.isScrolling) {
|
|
24251
|
-
this.browser.cancelTrackPan(); // event.preventDefault();
|
|
24252
|
-
// event.stopPropagation();
|
|
24253
|
-
|
|
24254
|
-
this.enableClick = false; // Until next mouse down
|
|
24255
|
-
} else {
|
|
24256
|
-
this.browser.cancelTrackPan();
|
|
24257
|
-
this.browser.endTrackDrag();
|
|
24258
|
-
}
|
|
24259
|
-
}
|
|
24260
|
-
|
|
24261
24223
|
function createClickState(event, viewport) {
|
|
24262
24224
|
const referenceFrame = viewport.referenceFrame;
|
|
24263
24225
|
const viewportCoords = translateMouseCoordinates$1(event, viewport.contentDiv);
|
|
24264
24226
|
const canvasCoords = translateMouseCoordinates$1(event, viewport.canvas);
|
|
24265
24227
|
const genomicLocation = referenceFrame.start + referenceFrame.toBP(viewportCoords.x);
|
|
24266
|
-
|
|
24267
|
-
if (undefined === genomicLocation || null === viewport.tile) {
|
|
24268
|
-
return undefined;
|
|
24269
|
-
}
|
|
24270
|
-
|
|
24271
24228
|
return {
|
|
24272
24229
|
event,
|
|
24273
24230
|
viewport,
|
|
@@ -24321,22 +24278,28 @@
|
|
|
24321
24278
|
return rows.join('');
|
|
24322
24279
|
}
|
|
24323
24280
|
|
|
24324
|
-
|
|
24325
|
-
|
|
24326
|
-
|
|
24327
|
-
|
|
24328
|
-
|
|
24329
|
-
|
|
24330
|
-
|
|
24331
|
-
|
|
24281
|
+
class FeatureCache {
|
|
24282
|
+
constructor(chr, tileStart, tileEnd, bpPerPixel, features, roiFeatures, multiresolution) {
|
|
24283
|
+
this.chr = chr;
|
|
24284
|
+
this.startBP = tileStart;
|
|
24285
|
+
this.endBP = tileEnd;
|
|
24286
|
+
this.bpPerPixel = bpPerPixel;
|
|
24287
|
+
this.features = features;
|
|
24288
|
+
this.roiFeatures = roiFeatures;
|
|
24289
|
+
this.multiresolution = multiresolution;
|
|
24290
|
+
}
|
|
24332
24291
|
|
|
24333
|
-
|
|
24334
|
-
|
|
24335
|
-
|
|
24292
|
+
containsRange(chr, start, end, bpPerPixel) {
|
|
24293
|
+
// For multi-resolution tracks allow for a 2X change in bpPerPixel
|
|
24294
|
+
const r = this.multiresolution ? this.bpPerPixel / bpPerPixel : 1;
|
|
24295
|
+
return start >= this.startBP && end <= this.endBP && chr === this.chr && r > 0.5 && r < 2;
|
|
24296
|
+
}
|
|
24336
24297
|
|
|
24337
|
-
|
|
24338
|
-
|
|
24339
|
-
|
|
24298
|
+
overlapsRange(chr, start, end) {
|
|
24299
|
+
return this.chr === chr && end >= this.startBP && start <= this.endBP;
|
|
24300
|
+
}
|
|
24301
|
+
|
|
24302
|
+
}
|
|
24340
24303
|
/**
|
|
24341
24304
|
* Merge 2 arrays. a and/or b can be undefined. If both are undefined, return undefined
|
|
24342
24305
|
* @param a An array or undefined
|
|
@@ -24475,10 +24438,12 @@
|
|
|
24475
24438
|
end: bp(this.rulerViewport.referenceFrame, left + width)
|
|
24476
24439
|
};
|
|
24477
24440
|
validateLocusExtent(this.rulerViewport.browser.genome.getChromosome(this.rulerViewport.referenceFrame.chr).bpLength, extent, this.rulerViewport.browser.minimumBases());
|
|
24478
|
-
|
|
24479
|
-
|
|
24480
|
-
this.rulerViewport.referenceFrame.
|
|
24481
|
-
this.rulerViewport.
|
|
24441
|
+
const newStart = Math.round(extent.start);
|
|
24442
|
+
const newEnd = Math.round(extent.end);
|
|
24443
|
+
this.rulerViewport.referenceFrame.bpPerPixel = (newEnd - newStart) / this.rulerViewport.contentDiv.clientWidth;
|
|
24444
|
+
this.rulerViewport.referenceFrame.start = newStart;
|
|
24445
|
+
this.rulerViewport.referenceFrame.end = newEnd;
|
|
24446
|
+
this.rulerViewport.browser.updateViews();
|
|
24482
24447
|
}
|
|
24483
24448
|
}
|
|
24484
24449
|
}
|
|
@@ -25480,6 +25445,18 @@
|
|
|
25480
25445
|
return true; // By definition
|
|
25481
25446
|
}
|
|
25482
25447
|
|
|
25448
|
+
isMateMapped() {
|
|
25449
|
+
return true; // By definition
|
|
25450
|
+
}
|
|
25451
|
+
|
|
25452
|
+
isProperPair() {
|
|
25453
|
+
return this.firstAlignment.isProperPair();
|
|
25454
|
+
}
|
|
25455
|
+
|
|
25456
|
+
get fragmentLength() {
|
|
25457
|
+
return Math.abs(this.firstAlignment.fragmentLength);
|
|
25458
|
+
}
|
|
25459
|
+
|
|
25483
25460
|
firstOfPairStrand() {
|
|
25484
25461
|
if (this.firstAlignment.isFirstOfPair()) {
|
|
25485
25462
|
return this.firstAlignment.strand;
|
|
@@ -25846,7 +25823,15 @@
|
|
|
25846
25823
|
*/
|
|
25847
25824
|
|
|
25848
25825
|
class AlignmentContainer {
|
|
25849
|
-
|
|
25826
|
+
// this.config.samplingWindowSize, this.config.samplingDepth,
|
|
25827
|
+
// this.config.pairsSupported, this.config.alleleFreqThreshold)
|
|
25828
|
+
constructor(chr, start, end, _ref) {
|
|
25829
|
+
let {
|
|
25830
|
+
samplingWindowSize,
|
|
25831
|
+
samplingDepth,
|
|
25832
|
+
pairsSupported,
|
|
25833
|
+
alleleFreqThreshold
|
|
25834
|
+
} = _ref;
|
|
25850
25835
|
this.chr = chr;
|
|
25851
25836
|
this.start = Math.floor(start);
|
|
25852
25837
|
this.end = Math.ceil(end);
|
|
@@ -25869,17 +25854,10 @@
|
|
|
25869
25854
|
// TODO -- pass this in
|
|
25870
25855
|
return alignment.isMapped() && !alignment.isFailsVendorQualityCheck();
|
|
25871
25856
|
};
|
|
25872
|
-
|
|
25873
|
-
this.pairedEndStats = new PairedEndStats();
|
|
25874
25857
|
}
|
|
25875
25858
|
|
|
25876
25859
|
push(alignment) {
|
|
25877
25860
|
if (this.filter(alignment) === false) return;
|
|
25878
|
-
|
|
25879
|
-
if (alignment.isPaired()) {
|
|
25880
|
-
this.pairedEndStats.push(alignment);
|
|
25881
|
-
}
|
|
25882
|
-
|
|
25883
25861
|
this.coverageMap.incCounts(alignment); // Count coverage before any downsampling
|
|
25884
25862
|
|
|
25885
25863
|
if (this.pairsSupported && this.downsampledReads.has(alignment.readName)) {
|
|
@@ -25908,7 +25886,6 @@
|
|
|
25908
25886
|
});
|
|
25909
25887
|
this.pairsCache = undefined;
|
|
25910
25888
|
this.downsampledReads = undefined;
|
|
25911
|
-
this.pairedEndStats.compute();
|
|
25912
25889
|
}
|
|
25913
25890
|
|
|
25914
25891
|
contains(chr, start, end) {
|
|
@@ -26203,62 +26180,6 @@
|
|
|
26203
26180
|
|
|
26204
26181
|
}
|
|
26205
26182
|
|
|
26206
|
-
class PairedEndStats {
|
|
26207
|
-
constructor(lowerPercentile, upperPercentile) {
|
|
26208
|
-
this.totalCount = 0;
|
|
26209
|
-
this.frCount = 0;
|
|
26210
|
-
this.rfCount = 0;
|
|
26211
|
-
this.ffCount = 0;
|
|
26212
|
-
this.sumF = 0;
|
|
26213
|
-
this.sumF2 = 0; //this.lp = lowerPercentile === undefined ? 0.005 : lowerPercentile;
|
|
26214
|
-
//this.up = upperPercentile === undefined ? 0.995 : upperPercentile;
|
|
26215
|
-
//this.digest = new Digest();
|
|
26216
|
-
}
|
|
26217
|
-
|
|
26218
|
-
push(alignment) {
|
|
26219
|
-
if (alignment.isProperPair()) {
|
|
26220
|
-
var fragmentLength = Math.abs(alignment.fragmentLength); //this.digest.push(fragmentLength);
|
|
26221
|
-
|
|
26222
|
-
this.sumF += fragmentLength;
|
|
26223
|
-
this.sumF2 += fragmentLength * fragmentLength;
|
|
26224
|
-
var po = alignment.pairOrientation;
|
|
26225
|
-
|
|
26226
|
-
if (typeof po === "string" && po.length === 4) {
|
|
26227
|
-
var tmp = '' + po.charAt(0) + po.charAt(2);
|
|
26228
|
-
|
|
26229
|
-
switch (tmp) {
|
|
26230
|
-
case 'FF':
|
|
26231
|
-
case 'RR':
|
|
26232
|
-
this.ffCount++;
|
|
26233
|
-
break;
|
|
26234
|
-
|
|
26235
|
-
case "FR":
|
|
26236
|
-
this.frCount++;
|
|
26237
|
-
break;
|
|
26238
|
-
|
|
26239
|
-
case "RF":
|
|
26240
|
-
this.rfCount++;
|
|
26241
|
-
}
|
|
26242
|
-
}
|
|
26243
|
-
|
|
26244
|
-
this.totalCount++;
|
|
26245
|
-
}
|
|
26246
|
-
}
|
|
26247
|
-
|
|
26248
|
-
compute() {
|
|
26249
|
-
if (this.totalCount > 100) {
|
|
26250
|
-
if (this.ffCount / this.totalCount > 0.9) this.orienation = "ff";else if (this.frCount / this.totalCount > 0.9) this.orienation = "fr";else if (this.rfCount / this.totalCount > 0.9) this.orienation = "rf";
|
|
26251
|
-
var fMean = this.sumF / this.totalCount;
|
|
26252
|
-
var stdDev = Math.sqrt((this.totalCount * this.sumF2 - this.sumF * this.sumF) / (this.totalCount * this.totalCount));
|
|
26253
|
-
this.lowerFragmentLength = fMean - 3 * stdDev;
|
|
26254
|
-
this.upperFragmentLength = fMean + 3 * stdDev; //this.lowerFragmentLength = this.digest.percentile(this.lp);
|
|
26255
|
-
//this.upperFragmentLength = this.digest.percentile(this.up);
|
|
26256
|
-
//this.digest = undefined;
|
|
26257
|
-
}
|
|
26258
|
-
}
|
|
26259
|
-
|
|
26260
|
-
}
|
|
26261
|
-
|
|
26262
26183
|
class SupplementaryAlignment {
|
|
26263
26184
|
constructor(rec) {
|
|
26264
26185
|
const tokens = rec.split(',');
|
|
@@ -27021,7 +26942,7 @@
|
|
|
27021
26942
|
const lseq = readInt(ba, offset + 20);
|
|
27022
26943
|
const mateChrIdx = readInt(ba, offset + 24);
|
|
27023
26944
|
const matePos = readInt(ba, offset + 28);
|
|
27024
|
-
const
|
|
26945
|
+
const fragmentLength = readInt(ba, offset + 32);
|
|
27025
26946
|
let readName = [];
|
|
27026
26947
|
|
|
27027
26948
|
for (let j = 0; j < nl - 1; ++j) {
|
|
@@ -27062,7 +26983,7 @@
|
|
|
27062
26983
|
alignment.readName = readName;
|
|
27063
26984
|
alignment.cigar = cigar;
|
|
27064
26985
|
alignment.lengthOnRef = lengthOnRef;
|
|
27065
|
-
alignment.fragmentLength =
|
|
26986
|
+
alignment.fragmentLength = fragmentLength;
|
|
27066
26987
|
alignment.mq = mq;
|
|
27067
26988
|
BamUtils.bam_tag2cigar(ba, blockEnd, p, lseq, alignment, cigarArray);
|
|
27068
26989
|
alignment.end = alignment.start + alignment.lengthOnRef;
|
|
@@ -27462,7 +27383,7 @@
|
|
|
27462
27383
|
const header = this.header;
|
|
27463
27384
|
const queryChr = header.chrAliasTable.hasOwnProperty(chr) ? header.chrAliasTable[chr] : chr;
|
|
27464
27385
|
const qAlignments = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd);
|
|
27465
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
27386
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config);
|
|
27466
27387
|
|
|
27467
27388
|
for (let a of qAlignments) {
|
|
27468
27389
|
alignmentContainer.push(a);
|
|
@@ -27489,13 +27410,13 @@
|
|
|
27489
27410
|
const alignments = [];
|
|
27490
27411
|
this.header = BamUtils.decodeBamHeader(data);
|
|
27491
27412
|
BamUtils.decodeBamRecords(data, this.header.size, alignments, this.header.chrNames);
|
|
27492
|
-
this.alignmentCache = new FeatureCache(alignments, this.genome);
|
|
27413
|
+
this.alignmentCache = new FeatureCache$1(alignments, this.genome);
|
|
27493
27414
|
}
|
|
27494
27415
|
|
|
27495
27416
|
fetchAlignments(chr, bpStart, bpEnd) {
|
|
27496
27417
|
const queryChr = this.header.chrAliasTable.hasOwnProperty(chr) ? this.header.chrAliasTable[chr] : chr;
|
|
27497
27418
|
const features = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd);
|
|
27498
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
27419
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config);
|
|
27499
27420
|
|
|
27500
27421
|
for (let feature of features) {
|
|
27501
27422
|
alignmentContainer.push(feature);
|
|
@@ -28495,7 +28416,7 @@
|
|
|
28495
28416
|
const chrToIndex = await this.getChrIndex();
|
|
28496
28417
|
const queryChr = this.chrAliasTable.hasOwnProperty(chr) ? this.chrAliasTable[chr] : chr;
|
|
28497
28418
|
const chrId = chrToIndex[queryChr];
|
|
28498
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config
|
|
28419
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config);
|
|
28499
28420
|
|
|
28500
28421
|
if (chrId === undefined) {
|
|
28501
28422
|
return alignmentContainer;
|
|
@@ -28644,7 +28565,7 @@
|
|
|
28644
28565
|
|
|
28645
28566
|
async readAlignments(chr, start, end) {
|
|
28646
28567
|
if (!this.bamReaders.hasOwnProperty(chr)) {
|
|
28647
|
-
return new AlignmentContainer(chr, start, end);
|
|
28568
|
+
return new AlignmentContainer(chr, start, end, this.config);
|
|
28648
28569
|
} else {
|
|
28649
28570
|
let reader = this.bamReaders[chr];
|
|
28650
28571
|
const a = await reader.readAlignments(chr, start, end);
|
|
@@ -28716,7 +28637,7 @@
|
|
|
28716
28637
|
return igvxhr.loadString(url, buildOptions(self.config)).then(function (sam) {
|
|
28717
28638
|
var alignmentContainer;
|
|
28718
28639
|
header.chrToIndex[queryChr];
|
|
28719
|
-
alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, self.
|
|
28640
|
+
alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, self.config);
|
|
28720
28641
|
BamUtils.decodeSamRecords(sam, alignmentContainer, queryChr, bpStart, bpEnd, self.filter);
|
|
28721
28642
|
return alignmentContainer;
|
|
28722
28643
|
});
|
|
@@ -28926,7 +28847,7 @@
|
|
|
28926
28847
|
|
|
28927
28848
|
const ba = unbgzf(compressedData.buffer);
|
|
28928
28849
|
const chrIdx = this.header.chrToIndex[chr];
|
|
28929
|
-
const alignmentContainer = new AlignmentContainer(chr, start, end, this.
|
|
28850
|
+
const alignmentContainer = new AlignmentContainer(chr, start, end, this.config);
|
|
28930
28851
|
BamUtils.decodeBamRecords(ba, this.header.size, alignmentContainer, this.header.chrNames, chrIdx, start, end);
|
|
28931
28852
|
alignmentContainer.finish();
|
|
28932
28853
|
return alignmentContainer;
|
|
@@ -44464,7 +44385,7 @@
|
|
|
44464
44385
|
const header = await this.getHeader();
|
|
44465
44386
|
const queryChr = header.chrAliasTable.hasOwnProperty(chr) ? header.chrAliasTable[chr] : chr;
|
|
44466
44387
|
const chrIdx = header.chrToIndex[queryChr];
|
|
44467
|
-
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.
|
|
44388
|
+
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config);
|
|
44468
44389
|
|
|
44469
44390
|
if (chrIdx === undefined) {
|
|
44470
44391
|
return alignmentContainer;
|
|
@@ -45073,7 +44994,7 @@
|
|
|
45073
44994
|
"pageSize": "10000"
|
|
45074
44995
|
},
|
|
45075
44996
|
decode: decodeGa4ghReads,
|
|
45076
|
-
results: new AlignmentContainer(chr, bpStart, bpEnd, self.
|
|
44997
|
+
results: new AlignmentContainer(chr, bpStart, bpEnd, self.config)
|
|
45077
44998
|
});
|
|
45078
44999
|
});
|
|
45079
45000
|
|
|
@@ -45380,7 +45301,6 @@
|
|
|
45380
45301
|
const genome = browser.genome;
|
|
45381
45302
|
this.config = config;
|
|
45382
45303
|
this.genome = genome;
|
|
45383
|
-
this.alignmentContainer = undefined;
|
|
45384
45304
|
|
|
45385
45305
|
if (isDataURL(config.url)) {
|
|
45386
45306
|
if ("cram" === config.format) {
|
|
@@ -45431,58 +45351,44 @@
|
|
|
45431
45351
|
}
|
|
45432
45352
|
|
|
45433
45353
|
setViewAsPairs(bool) {
|
|
45434
|
-
|
|
45435
|
-
if (this.viewAsPairs !== bool) {
|
|
45436
|
-
this.viewAsPairs = bool; // if (this.alignmentContainer) {
|
|
45437
|
-
// this.alignmentContainer.setViewAsPairs(bool);
|
|
45438
|
-
// }
|
|
45439
|
-
}
|
|
45354
|
+
this.viewAsPairs = bool;
|
|
45440
45355
|
}
|
|
45441
45356
|
|
|
45442
45357
|
setShowSoftClips(bool) {
|
|
45443
|
-
|
|
45444
|
-
this.showSoftClips = bool;
|
|
45445
|
-
}
|
|
45358
|
+
this.showSoftClips = bool;
|
|
45446
45359
|
}
|
|
45447
45360
|
|
|
45448
45361
|
async getAlignments(chr, bpStart, bpEnd) {
|
|
45449
45362
|
const genome = this.genome;
|
|
45450
45363
|
const showSoftClips = this.showSoftClips;
|
|
45364
|
+
const alignmentContainer = await this.bamReader.readAlignments(chr, bpStart, bpEnd);
|
|
45365
|
+
let alignments = alignmentContainer.alignments;
|
|
45451
45366
|
|
|
45452
|
-
if (this.
|
|
45453
|
-
|
|
45454
|
-
|
|
45455
|
-
|
|
45456
|
-
|
|
45457
|
-
|
|
45458
|
-
if (!this.viewAsPairs) {
|
|
45459
|
-
alignments = unpairAlignments([{
|
|
45460
|
-
alignments: alignments
|
|
45461
|
-
}]);
|
|
45462
|
-
}
|
|
45463
|
-
|
|
45464
|
-
const hasAlignments = alignments.length > 0;
|
|
45465
|
-
alignmentContainer.packedAlignmentRows = packAlignmentRows(alignments, alignmentContainer.start, alignmentContainer.end, showSoftClips);
|
|
45466
|
-
alignmentContainer.alignments = undefined; // Don't need to hold onto these anymore
|
|
45367
|
+
if (!this.viewAsPairs) {
|
|
45368
|
+
alignments = unpairAlignments([{
|
|
45369
|
+
alignments: alignments
|
|
45370
|
+
}]);
|
|
45371
|
+
}
|
|
45467
45372
|
|
|
45468
|
-
|
|
45373
|
+
const hasAlignments = alignments.length > 0;
|
|
45374
|
+
alignmentContainer.packedAlignmentRows = packAlignmentRows(alignments, alignmentContainer.start, alignmentContainer.end, showSoftClips);
|
|
45375
|
+
this.alignmentContainer = alignmentContainer;
|
|
45469
45376
|
|
|
45470
|
-
|
|
45471
|
-
|
|
45377
|
+
if (hasAlignments) {
|
|
45378
|
+
const sequence = await genome.sequence.getSequence(chr, alignmentContainer.start, alignmentContainer.end);
|
|
45472
45379
|
|
|
45473
|
-
|
|
45474
|
-
|
|
45380
|
+
if (sequence) {
|
|
45381
|
+
alignmentContainer.coverageMap.refSeq = sequence; // TODO -- fix this
|
|
45475
45382
|
|
|
45476
|
-
|
|
45383
|
+
alignmentContainer.sequence = sequence; // TODO -- fix this
|
|
45477
45384
|
|
|
45478
|
-
|
|
45479
|
-
|
|
45480
|
-
|
|
45481
|
-
}
|
|
45385
|
+
return alignmentContainer;
|
|
45386
|
+
} else {
|
|
45387
|
+
console.error("No sequence for: " + chr + ":" + alignmentContainer.start + "-" + alignmentContainer.end);
|
|
45482
45388
|
}
|
|
45483
|
-
|
|
45484
|
-
return alignmentContainer;
|
|
45485
45389
|
}
|
|
45390
|
+
|
|
45391
|
+
return alignmentContainer;
|
|
45486
45392
|
}
|
|
45487
45393
|
|
|
45488
45394
|
}
|
|
@@ -45666,7 +45572,7 @@
|
|
|
45666
45572
|
return state;
|
|
45667
45573
|
}
|
|
45668
45574
|
|
|
45669
|
-
supportsWholeGenome() {
|
|
45575
|
+
get supportsWholeGenome() {
|
|
45670
45576
|
return false;
|
|
45671
45577
|
}
|
|
45672
45578
|
/**
|
|
@@ -45827,7 +45733,7 @@
|
|
|
45827
45733
|
clickedFeatures(clickState, features) {
|
|
45828
45734
|
// We use the cached features rather than method to avoid async load. If the
|
|
45829
45735
|
// feature is not already loaded this won't work, but the user wouldn't be mousing over it either.
|
|
45830
|
-
if (!features) features = clickState.viewport.
|
|
45736
|
+
if (!features) features = clickState.viewport.cachedFeatures;
|
|
45831
45737
|
|
|
45832
45738
|
if (!features || features.length === 0) {
|
|
45833
45739
|
return [];
|
|
@@ -48466,52 +48372,125 @@
|
|
|
48466
48372
|
return regions;
|
|
48467
48373
|
}
|
|
48468
48374
|
|
|
48375
|
+
function sendChords(chords, track, refFrame, alpha) {
|
|
48376
|
+
const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? track.color : getChrColor(refFrame.chr), alpha);
|
|
48377
|
+
const trackColor = IGVColor.addAlpha(track.color || 'rgb(0,0,255)', alpha); // name the chord set to include locus and filtering information
|
|
48378
|
+
|
|
48379
|
+
const encodedName = track.name.replaceAll(' ', '%20');
|
|
48380
|
+
const chordSetName = "all" === refFrame.chr ? encodedName : `${encodedName} ${refFrame.chr}:${refFrame.start}-${refFrame.end}`;
|
|
48381
|
+
track.browser.circularView.addChords(chords, {
|
|
48382
|
+
track: chordSetName,
|
|
48383
|
+
color: chordSetColor,
|
|
48384
|
+
trackColor: trackColor
|
|
48385
|
+
}); // show circular view if hidden
|
|
48386
|
+
|
|
48387
|
+
if (!track.browser.circularViewVisible) track.browser.circularViewVisible = true;
|
|
48388
|
+
}
|
|
48389
|
+
|
|
48469
48390
|
function createCircularView(el, browser) {
|
|
48470
48391
|
const circularView = new CircularView(el, {
|
|
48471
48392
|
onChordClick: (feature, chordTrack, pluginManager) => {
|
|
48472
48393
|
const f1 = feature.data;
|
|
48473
48394
|
const f2 = f1.mate;
|
|
48474
|
-
|
|
48475
|
-
|
|
48476
|
-
|
|
48477
|
-
|
|
48478
|
-
|
|
48479
|
-
|
|
48480
|
-
|
|
48481
|
-
|
|
48482
|
-
|
|
48483
|
-
|
|
48484
|
-
|
|
48485
|
-
|
|
48486
|
-
|
|
48487
|
-
|
|
48488
|
-
|
|
48489
|
-
|
|
48490
|
-
|
|
48491
|
-
if (!loci.some(locus => {
|
|
48492
|
-
return locus.contains(l);
|
|
48493
|
-
})) {
|
|
48494
|
-
// add flanking
|
|
48495
|
-
l.start = Math.max(0, l.start - flanking);
|
|
48496
|
-
l.end += flanking;
|
|
48497
|
-
loci.push(l);
|
|
48395
|
+
addFrameForFeature(f1);
|
|
48396
|
+
addFrameForFeature(f2);
|
|
48397
|
+
|
|
48398
|
+
function addFrameForFeature(feature) {
|
|
48399
|
+
feature.chr = browser.genome.getChromosomeName(feature.refName);
|
|
48400
|
+
let frameFound = false;
|
|
48401
|
+
|
|
48402
|
+
for (let referenceFrame of browser.referenceFrameList) {
|
|
48403
|
+
const l = Locus.fromLocusString(referenceFrame.getLocusString());
|
|
48404
|
+
|
|
48405
|
+
if (l.contains(feature)) {
|
|
48406
|
+
frameFound = true;
|
|
48407
|
+
break;
|
|
48408
|
+
} else if (l.overlaps(feature)) {
|
|
48409
|
+
referenceFrame.extend(feature);
|
|
48410
|
+
frameFound = true;
|
|
48411
|
+
break;
|
|
48498
48412
|
}
|
|
48499
48413
|
}
|
|
48500
|
-
} else {
|
|
48501
|
-
l1.start = Math.max(0, l1.start - flanking);
|
|
48502
|
-
l1.end += flanking;
|
|
48503
|
-
l2.start = Math.max(0, l2.start - flanking);
|
|
48504
|
-
l2.end += flanking;
|
|
48505
|
-
loci = [l1, l2];
|
|
48506
|
-
}
|
|
48507
48414
|
|
|
48508
|
-
|
|
48509
|
-
|
|
48415
|
+
if (!frameFound) {
|
|
48416
|
+
const flanking = 2000;
|
|
48417
|
+
const center = (feature.start + feature.end) / 2;
|
|
48418
|
+
browser.addMultiLocusPanel(feature.chr, center - flanking, center + flanking);
|
|
48419
|
+
}
|
|
48420
|
+
}
|
|
48510
48421
|
}
|
|
48511
48422
|
});
|
|
48512
48423
|
return circularView;
|
|
48513
48424
|
}
|
|
48514
48425
|
|
|
48426
|
+
class PairedEndStats {
|
|
48427
|
+
constructor(alignments, _ref) {
|
|
48428
|
+
let {
|
|
48429
|
+
minTLENPercentile,
|
|
48430
|
+
maxTLENPercentile
|
|
48431
|
+
} = _ref;
|
|
48432
|
+
this.totalCount = 0;
|
|
48433
|
+
this.frCount = 0;
|
|
48434
|
+
this.rfCount = 0;
|
|
48435
|
+
this.ffCount = 0;
|
|
48436
|
+
this.sumF = 0;
|
|
48437
|
+
this.sumF2 = 0;
|
|
48438
|
+
this.lp = minTLENPercentile === undefined ? 0.1 : minTLENPercentile;
|
|
48439
|
+
this.up = maxTLENPercentile === undefined ? 99.5 : maxTLENPercentile;
|
|
48440
|
+
this.isizes = [];
|
|
48441
|
+
this.compute(alignments);
|
|
48442
|
+
}
|
|
48443
|
+
|
|
48444
|
+
compute(alignments) {
|
|
48445
|
+
for (let alignment of alignments) {
|
|
48446
|
+
if (alignment.isProperPair()) {
|
|
48447
|
+
var tlen = Math.abs(alignment.fragmentLength);
|
|
48448
|
+
this.sumF += tlen;
|
|
48449
|
+
this.sumF2 += tlen * tlen;
|
|
48450
|
+
this.isizes.push(tlen);
|
|
48451
|
+
var po = alignment.pairOrientation;
|
|
48452
|
+
|
|
48453
|
+
if (typeof po === "string" && po.length === 4) {
|
|
48454
|
+
var tmp = '' + po.charAt(0) + po.charAt(2);
|
|
48455
|
+
|
|
48456
|
+
switch (tmp) {
|
|
48457
|
+
case 'FF':
|
|
48458
|
+
case 'RR':
|
|
48459
|
+
this.ffCount++;
|
|
48460
|
+
break;
|
|
48461
|
+
|
|
48462
|
+
case "FR":
|
|
48463
|
+
this.frCount++;
|
|
48464
|
+
break;
|
|
48465
|
+
|
|
48466
|
+
case "RF":
|
|
48467
|
+
this.rfCount++;
|
|
48468
|
+
}
|
|
48469
|
+
}
|
|
48470
|
+
|
|
48471
|
+
this.totalCount++;
|
|
48472
|
+
}
|
|
48473
|
+
}
|
|
48474
|
+
|
|
48475
|
+
if (this.ffCount / this.totalCount > 0.9) this.orienation = "ff";else if (this.frCount / this.totalCount > 0.9) this.orienation = "fr";else if (this.rfCount / this.totalCount > 0.9) this.orienation = "rf";
|
|
48476
|
+
this.minTLEN = this.lp === 0 ? 0 : percentile(this.isizes, this.lp);
|
|
48477
|
+
this.maxTLEN = percentile(this.isizes, this.up); // var fMean = this.sumF / this.totalCount
|
|
48478
|
+
// var stdDev = Math.sqrt((this.totalCount * this.sumF2 - this.sumF * this.sumF) / (this.totalCount * this.totalCount))
|
|
48479
|
+
// this.minTLEN = fMean - 3 * stdDev
|
|
48480
|
+
// this.maxTLEN = fMean + 3 * stdDev
|
|
48481
|
+
}
|
|
48482
|
+
|
|
48483
|
+
}
|
|
48484
|
+
|
|
48485
|
+
function percentile(array, p) {
|
|
48486
|
+
if (array.length === 0) return undefined;
|
|
48487
|
+
var k = Math.floor(array.length * (p / 100));
|
|
48488
|
+
array.sort(function (a, b) {
|
|
48489
|
+
return a - b;
|
|
48490
|
+
});
|
|
48491
|
+
return array[k];
|
|
48492
|
+
}
|
|
48493
|
+
|
|
48515
48494
|
/*
|
|
48516
48495
|
* The MIT License (MIT)
|
|
48517
48496
|
*
|
|
@@ -48571,10 +48550,7 @@
|
|
|
48571
48550
|
this.showInsertions = false !== config.showInsertions;
|
|
48572
48551
|
this.showMismatches = false !== config.showMismatches;
|
|
48573
48552
|
this.color = config.color;
|
|
48574
|
-
this.coverageColor = config.coverageColor;
|
|
48575
|
-
this.minFragmentLength = config.minFragmentLength; // Optional, might be undefined
|
|
48576
|
-
|
|
48577
|
-
this.maxFragmentLength = config.maxFragmentLength || 1000; // The sort object can be an array in the case of multi-locus view, however if multiple sort positions
|
|
48553
|
+
this.coverageColor = config.coverageColor; // The sort object can be an array in the case of multi-locus view, however if multiple sort positions
|
|
48578
48554
|
// are present for a given reference frame the last one will take precedence
|
|
48579
48555
|
|
|
48580
48556
|
if (config.sort) {
|
|
@@ -48602,12 +48578,22 @@
|
|
|
48602
48578
|
return this._height;
|
|
48603
48579
|
}
|
|
48604
48580
|
|
|
48581
|
+
get minTemplateLength() {
|
|
48582
|
+
const configMinTLEN = this.config.minTLEN !== undefined ? this.config.minTLEN : this.config.minFragmentLength;
|
|
48583
|
+
return configMinTLEN !== undefined ? configMinTLEN : this._pairedEndStats ? this._pairedEndStats.minTLEN : 0;
|
|
48584
|
+
}
|
|
48585
|
+
|
|
48586
|
+
get maxTemplateLength() {
|
|
48587
|
+
const configMaxTLEN = this.config.maxTLEN !== undefined ? this.config.maxTLEN : this.config.maxFragmentLength;
|
|
48588
|
+
return configMaxTLEN !== undefined ? configMaxTLEN : this._pairedEndStats ? this._pairedEndStats.maxTLEN : 1000;
|
|
48589
|
+
}
|
|
48590
|
+
|
|
48605
48591
|
sort(options) {
|
|
48606
48592
|
options = this.assignSort(options);
|
|
48607
48593
|
|
|
48608
48594
|
for (let vp of this.trackView.viewports) {
|
|
48609
48595
|
if (vp.containsPosition(options.chr, options.position)) {
|
|
48610
|
-
const alignmentContainer = vp.
|
|
48596
|
+
const alignmentContainer = vp.cachedFeatures;
|
|
48611
48597
|
|
|
48612
48598
|
if (alignmentContainer) {
|
|
48613
48599
|
sortAlignmentRows(options, alignmentContainer);
|
|
@@ -48642,16 +48628,16 @@
|
|
|
48642
48628
|
async getFeatures(chr, bpStart, bpEnd, bpPerPixel, viewport) {
|
|
48643
48629
|
const alignmentContainer = await this.featureSource.getAlignments(chr, bpStart, bpEnd);
|
|
48644
48630
|
|
|
48645
|
-
if (alignmentContainer.
|
|
48646
|
-
|
|
48647
|
-
this.minFragmentLength = alignmentContainer.pairedEndStats.lowerFragmentLength;
|
|
48648
|
-
}
|
|
48631
|
+
if (alignmentContainer.paired && !this._pairedEndStats && !this.config.maxFragmentLength) {
|
|
48632
|
+
const pairedEndStats = new PairedEndStats(alignmentContainer.alignments, this.config);
|
|
48649
48633
|
|
|
48650
|
-
if (
|
|
48651
|
-
this.
|
|
48634
|
+
if (pairedEndStats.totalCount > 99) {
|
|
48635
|
+
this._pairedEndStats = pairedEndStats;
|
|
48652
48636
|
}
|
|
48653
48637
|
}
|
|
48654
48638
|
|
|
48639
|
+
alignmentContainer.alignments = undefined; // Don't need to hold onto these anymore
|
|
48640
|
+
|
|
48655
48641
|
const sort = this.sortObject;
|
|
48656
48642
|
|
|
48657
48643
|
if (sort) {
|
|
@@ -48756,7 +48742,7 @@
|
|
|
48756
48742
|
label: 'pair orientation'
|
|
48757
48743
|
});
|
|
48758
48744
|
colorByMenuItems.push({
|
|
48759
|
-
key: '
|
|
48745
|
+
key: 'tlen',
|
|
48760
48746
|
label: 'insert size (TLEN)'
|
|
48761
48747
|
});
|
|
48762
48748
|
colorByMenuItems.push({
|
|
@@ -48867,36 +48853,19 @@
|
|
|
48867
48853
|
this.trackView.repaintViews();
|
|
48868
48854
|
}
|
|
48869
48855
|
});
|
|
48870
|
-
} //
|
|
48856
|
+
} // Add chords to JBrowse circular view, if present
|
|
48871
48857
|
|
|
48872
48858
|
|
|
48873
|
-
if (this.browser.circularView &&
|
|
48859
|
+
if (this.browser.circularView && (this.alignmentTrack.hasPairs || this.alignmentTrack.hasSupplemental)) {
|
|
48874
48860
|
menuItems.push('<hr/>');
|
|
48875
48861
|
|
|
48876
48862
|
if (this.alignmentTrack.hasPairs) {
|
|
48877
48863
|
menuItems.push({
|
|
48878
48864
|
label: 'Add discordant pairs to circular view',
|
|
48879
48865
|
click: () => {
|
|
48880
|
-
const maxFragmentLength = this.maxFragmentLength;
|
|
48881
|
-
const inView = [];
|
|
48882
|
-
|
|
48883
48866
|
for (let viewport of this.trackView.viewports) {
|
|
48884
|
-
|
|
48885
|
-
const referenceFrame = viewport.referenceFrame;
|
|
48886
|
-
|
|
48887
|
-
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxFragmentLength)) {
|
|
48888
|
-
inView.push(a);
|
|
48889
|
-
}
|
|
48890
|
-
}
|
|
48867
|
+
this.addPairedChordsForViewport(viewport);
|
|
48891
48868
|
}
|
|
48892
|
-
|
|
48893
|
-
this.browser.circularViewVisible = true;
|
|
48894
|
-
const chords = makePairedAlignmentChords(inView);
|
|
48895
|
-
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02);
|
|
48896
|
-
this.browser.circularView.addChords(chords, {
|
|
48897
|
-
track: this.name,
|
|
48898
|
-
color: color
|
|
48899
|
-
});
|
|
48900
48869
|
}
|
|
48901
48870
|
});
|
|
48902
48871
|
}
|
|
@@ -48905,25 +48874,9 @@
|
|
|
48905
48874
|
menuItems.push({
|
|
48906
48875
|
label: 'Add split reads to circular view',
|
|
48907
48876
|
click: () => {
|
|
48908
|
-
const inView = [];
|
|
48909
|
-
|
|
48910
48877
|
for (let viewport of this.trackView.viewports) {
|
|
48911
|
-
|
|
48912
|
-
const referenceFrame = viewport.referenceFrame;
|
|
48913
|
-
const sa = a.hasTag('SA');
|
|
48914
|
-
|
|
48915
|
-
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && sa) {
|
|
48916
|
-
inView.push(a);
|
|
48917
|
-
}
|
|
48918
|
-
}
|
|
48878
|
+
this.addSplitChordsForViewport(viewport);
|
|
48919
48879
|
}
|
|
48920
|
-
|
|
48921
|
-
const chords = makeSupplementalAlignmentChords(inView);
|
|
48922
|
-
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.1);
|
|
48923
|
-
this.browser.circularView.addChords(chords, {
|
|
48924
|
-
track: this.name,
|
|
48925
|
-
color: color
|
|
48926
|
-
});
|
|
48927
48880
|
}
|
|
48928
48881
|
});
|
|
48929
48882
|
}
|
|
@@ -49042,7 +48995,7 @@
|
|
|
49042
48995
|
}
|
|
49043
48996
|
|
|
49044
48997
|
getCachedAlignmentContainers() {
|
|
49045
|
-
return this.trackView.viewports.map(vp => vp.
|
|
48998
|
+
return this.trackView.viewports.map(vp => vp.cachedFeatures);
|
|
49046
48999
|
}
|
|
49047
49000
|
|
|
49048
49001
|
get dataRange() {
|
|
@@ -49068,6 +49021,56 @@
|
|
|
49068
49021
|
set autoscale(autoscale) {
|
|
49069
49022
|
this.coverageTrack.autoscale = autoscale;
|
|
49070
49023
|
}
|
|
49024
|
+
/**
|
|
49025
|
+
* Add chords to the circular view for the given viewport, represented by its reference frame
|
|
49026
|
+
* @param refFrame
|
|
49027
|
+
*/
|
|
49028
|
+
|
|
49029
|
+
|
|
49030
|
+
addPairedChordsForViewport(viewport) {
|
|
49031
|
+
const maxTemplateLength = this.maxTemplateLength;
|
|
49032
|
+
const inView = [];
|
|
49033
|
+
const refFrame = viewport.referenceFrame;
|
|
49034
|
+
|
|
49035
|
+
for (let a of viewport.cachedFeatures.allAlignments()) {
|
|
49036
|
+
if (a.end >= refFrame.start && a.start <= refFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxTemplateLength)) {
|
|
49037
|
+
inView.push(a);
|
|
49038
|
+
}
|
|
49039
|
+
}
|
|
49040
|
+
|
|
49041
|
+
const chords = makePairedAlignmentChords(inView);
|
|
49042
|
+
sendChords(chords, this, refFrame, 0.02); // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
|
|
49043
|
+
// const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
|
|
49044
|
+
//
|
|
49045
|
+
// // name the chord set to include track name and locus
|
|
49046
|
+
// const encodedName = this.name.replaceAll(' ', '%20')
|
|
49047
|
+
// const chordSetName = "all" === refFrame.chr ? encodedName :
|
|
49048
|
+
// `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
|
|
49049
|
+
// this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
49050
|
+
}
|
|
49051
|
+
|
|
49052
|
+
addSplitChordsForViewport(viewport) {
|
|
49053
|
+
const inView = [];
|
|
49054
|
+
const refFrame = viewport.referenceFrame;
|
|
49055
|
+
|
|
49056
|
+
for (let a of viewport.cachedFeatures.allAlignments()) {
|
|
49057
|
+
const sa = a.hasTag('SA');
|
|
49058
|
+
|
|
49059
|
+
if (a.end >= refFrame.start && a.start <= refFrame.end && sa) {
|
|
49060
|
+
inView.push(a);
|
|
49061
|
+
}
|
|
49062
|
+
}
|
|
49063
|
+
|
|
49064
|
+
const chords = makeSupplementalAlignmentChords(inView);
|
|
49065
|
+
sendChords(chords, this, refFrame, 0.02); // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
|
|
49066
|
+
// const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
|
|
49067
|
+
//
|
|
49068
|
+
// // name the chord set to include track name and locus
|
|
49069
|
+
// const encodedName = this.name.replaceAll(' ', '%20')
|
|
49070
|
+
// const chordSetName = "all" === refFrame.chr ? encodedName :
|
|
49071
|
+
// `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
|
|
49072
|
+
// this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
49073
|
+
}
|
|
49071
49074
|
|
|
49072
49075
|
}
|
|
49073
49076
|
|
|
@@ -49178,7 +49181,7 @@
|
|
|
49178
49181
|
}
|
|
49179
49182
|
|
|
49180
49183
|
getClickedObject(clickState) {
|
|
49181
|
-
let features = clickState.viewport.
|
|
49184
|
+
let features = clickState.viewport.cachedFeatures;
|
|
49182
49185
|
if (!features || features.length === 0) return;
|
|
49183
49186
|
const genomicLocation = Math.floor(clickState.genomicLocation);
|
|
49184
49187
|
const coverageMap = features.coverageMap;
|
|
@@ -49264,14 +49267,14 @@
|
|
|
49264
49267
|
this.deletionColor = config.deletionColor || "black";
|
|
49265
49268
|
this.skippedColor = config.skippedColor || "rgb(150, 170, 170)";
|
|
49266
49269
|
this.pairConnectorColor = config.pairConnectorColor;
|
|
49267
|
-
this.
|
|
49268
|
-
this.
|
|
49270
|
+
this.smallTLENColor = config.smallTLENColor || config.smallFragmentLengthColor || "rgb(0, 0, 150)";
|
|
49271
|
+
this.largeTLENColor = config.largeTLENColor || config.largeFragmentLengthColor || "rgb(200, 0, 0)";
|
|
49269
49272
|
this.pairOrientation = config.pairOrienation || 'fr';
|
|
49270
49273
|
this.pairColors = {};
|
|
49271
49274
|
this.pairColors["RL"] = config.rlColor || "rgb(0, 150, 0)";
|
|
49272
49275
|
this.pairColors["RR"] = config.rrColor || "rgb(20, 50, 200)";
|
|
49273
49276
|
this.pairColors["LL"] = config.llColor || "rgb(0, 150, 150)";
|
|
49274
|
-
this.colorBy = config.colorBy || "
|
|
49277
|
+
this.colorBy = config.colorBy || "unexpectedPair";
|
|
49275
49278
|
this.colorByTag = config.colorByTag ? config.colorByTag.toUpperCase() : undefined;
|
|
49276
49279
|
this.bamColorTag = config.bamColorTag === undefined ? "YC" : config.bamColorTag;
|
|
49277
49280
|
this.hideSmallIndels = config.hideSmallIndels;
|
|
@@ -49370,7 +49373,7 @@
|
|
|
49370
49373
|
for (let alignment of alignmentRow.alignments) {
|
|
49371
49374
|
this.hasPairs = this.hasPairs || alignment.isPaired();
|
|
49372
49375
|
|
|
49373
|
-
if (this.browser.circularView
|
|
49376
|
+
if (this.browser.circularView) {
|
|
49374
49377
|
// This is an expensive check, only do it if needed
|
|
49375
49378
|
this.hasSupplemental = this.hasSupplemental || alignment.hasTag('SA');
|
|
49376
49379
|
}
|
|
@@ -49626,7 +49629,7 @@
|
|
|
49626
49629
|
direction: direction
|
|
49627
49630
|
};
|
|
49628
49631
|
this.parent.sortObject = newSortObject;
|
|
49629
|
-
sortAlignmentRows(newSortObject, viewport.
|
|
49632
|
+
sortAlignmentRows(newSortObject, viewport.cachedFeatures);
|
|
49630
49633
|
viewport.repaint();
|
|
49631
49634
|
};
|
|
49632
49635
|
|
|
@@ -49678,7 +49681,7 @@
|
|
|
49678
49681
|
};
|
|
49679
49682
|
this.sortByTag = tag;
|
|
49680
49683
|
this.parent.sortObject = newSortObject;
|
|
49681
|
-
sortAlignmentRows(newSortObject, viewport.
|
|
49684
|
+
sortAlignmentRows(newSortObject, viewport.cachedFeatures);
|
|
49682
49685
|
viewport.repaint();
|
|
49683
49686
|
}
|
|
49684
49687
|
}
|
|
@@ -49702,8 +49705,12 @@
|
|
|
49702
49705
|
const referenceFrame = clickState.viewport.referenceFrame;
|
|
49703
49706
|
|
|
49704
49707
|
if (this.browser.genome.getChromosome(clickedAlignment.mate.chr)) {
|
|
49705
|
-
this.highlightedAlignmentReadNamed = clickedAlignment.readName;
|
|
49706
|
-
|
|
49708
|
+
this.highlightedAlignmentReadNamed = clickedAlignment.readName; //this.browser.presentMultiLocusPanel(clickedAlignment, referenceFrame)
|
|
49709
|
+
|
|
49710
|
+
const bpWidth = referenceFrame.end - referenceFrame.start;
|
|
49711
|
+
const frameStart = clickedAlignment.mate.position - bpWidth / 2;
|
|
49712
|
+
const frameEnd = clickedAlignment.mate.position + bpWidth / 2;
|
|
49713
|
+
this.browser.addMultiLocusPanel(clickedAlignment.mate.chr, frameStart, frameEnd, referenceFrame);
|
|
49707
49714
|
} else {
|
|
49708
49715
|
Alert.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
|
|
49709
49716
|
}
|
|
@@ -49716,9 +49723,7 @@
|
|
|
49716
49723
|
list.push({
|
|
49717
49724
|
label: 'View read sequence',
|
|
49718
49725
|
click: () => {
|
|
49719
|
-
const
|
|
49720
|
-
if (!alignment) return;
|
|
49721
|
-
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
49726
|
+
const seqstring = clickedAlignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
49722
49727
|
|
|
49723
49728
|
if (!seqstring || "*" === seqstring) {
|
|
49724
49729
|
Alert.presentAlert("Read sequence: *");
|
|
@@ -49731,12 +49736,16 @@
|
|
|
49731
49736
|
if (isSecureContext()) {
|
|
49732
49737
|
list.push({
|
|
49733
49738
|
label: 'Copy read sequence',
|
|
49734
|
-
click: () => {
|
|
49735
|
-
const
|
|
49736
|
-
if (!alignment) return;
|
|
49737
|
-
const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
49739
|
+
click: async () => {
|
|
49740
|
+
const seq = clickedAlignment.seq; //.map(b => String.fromCharCode(b)).join("");
|
|
49738
49741
|
|
|
49739
|
-
|
|
49742
|
+
try {
|
|
49743
|
+
//console.log(`seq: ${seq}`)
|
|
49744
|
+
await navigator.clipboard.writeText(seq);
|
|
49745
|
+
} catch (e) {
|
|
49746
|
+
console.error(e);
|
|
49747
|
+
Alert.presentAlert(`error copying sequence to clipboard ${e}`);
|
|
49748
|
+
}
|
|
49740
49749
|
}
|
|
49741
49750
|
});
|
|
49742
49751
|
}
|
|
@@ -49746,25 +49755,12 @@
|
|
|
49746
49755
|
} // Experimental JBrowse feature
|
|
49747
49756
|
|
|
49748
49757
|
|
|
49749
|
-
if (this.browser.circularView &&
|
|
49758
|
+
if (this.browser.circularView && (this.hasPairs || this.hasSupplemental)) {
|
|
49750
49759
|
if (this.hasPairs) {
|
|
49751
49760
|
list.push({
|
|
49752
49761
|
label: 'Add discordant pairs to circular view',
|
|
49753
49762
|
click: () => {
|
|
49754
|
-
|
|
49755
|
-
const {
|
|
49756
|
-
referenceFrame
|
|
49757
|
-
} = viewport;
|
|
49758
|
-
const inView = viewport.getCachedFeatures().allAlignments().filter(a => {
|
|
49759
|
-
return a.end >= referenceFrame.start && a.start <= referenceFrame.end && a.mate && a.mate.chr && (a.mate.chr !== a.chr || Math.max(a.fragmentLength) > maxFragmentLength);
|
|
49760
|
-
});
|
|
49761
|
-
this.browser.circularViewVisible = true;
|
|
49762
|
-
const chords = makePairedAlignmentChords(inView);
|
|
49763
|
-
const color = IGVColor.addAlpha(this.parent.color || 'rgb(0,0,255)', 0.02);
|
|
49764
|
-
this.browser.circularView.addChords(chords, {
|
|
49765
|
-
track: this.parent.name,
|
|
49766
|
-
color: color
|
|
49767
|
-
});
|
|
49763
|
+
this.parent.addPairedChordsForViewport(viewport);
|
|
49768
49764
|
}
|
|
49769
49765
|
});
|
|
49770
49766
|
}
|
|
@@ -49773,23 +49769,7 @@
|
|
|
49773
49769
|
list.push({
|
|
49774
49770
|
label: 'Add split reads to circular view',
|
|
49775
49771
|
click: () => {
|
|
49776
|
-
|
|
49777
|
-
|
|
49778
|
-
for (let a of viewport.getCachedFeatures().allAlignments()) {
|
|
49779
|
-
const referenceFrame = viewport.referenceFrame;
|
|
49780
|
-
const sa = a.hasTag('SA');
|
|
49781
|
-
|
|
49782
|
-
if (a.end >= referenceFrame.start && a.start <= referenceFrame.end && sa) {
|
|
49783
|
-
inView.push(a);
|
|
49784
|
-
}
|
|
49785
|
-
}
|
|
49786
|
-
|
|
49787
|
-
const chords = makeSupplementalAlignmentChords(inView);
|
|
49788
|
-
const color = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.1);
|
|
49789
|
-
this.browser.circularView.addChords(chords, {
|
|
49790
|
-
track: this.name,
|
|
49791
|
-
color: color
|
|
49792
|
-
});
|
|
49772
|
+
this.parent.addSplitChordsForViewport(viewport);
|
|
49793
49773
|
}
|
|
49794
49774
|
});
|
|
49795
49775
|
}
|
|
@@ -49805,7 +49785,7 @@
|
|
|
49805
49785
|
const y = clickState.y;
|
|
49806
49786
|
const genomicLocation = clickState.genomicLocation;
|
|
49807
49787
|
const showSoftClips = this.parent.showSoftClips;
|
|
49808
|
-
let features = viewport.
|
|
49788
|
+
let features = viewport.cachedFeatures;
|
|
49809
49789
|
if (!features || features.length === 0) return;
|
|
49810
49790
|
let packedAlignmentRows = features.packedAlignmentRows;
|
|
49811
49791
|
let downsampledIntervals = features.downsampledIntervals;
|
|
@@ -49891,13 +49871,16 @@
|
|
|
49891
49871
|
break;
|
|
49892
49872
|
}
|
|
49893
49873
|
|
|
49874
|
+
case "tlen":
|
|
49894
49875
|
case "fragmentLength":
|
|
49895
|
-
if (alignment.mate && alignment.isMateMapped()
|
|
49896
|
-
|
|
49897
|
-
|
|
49898
|
-
|
|
49899
|
-
|
|
49900
|
-
|
|
49876
|
+
if (alignment.mate && alignment.isMateMapped()) {
|
|
49877
|
+
if (alignment.mate.chr !== alignment.chr) {
|
|
49878
|
+
color = getChrColor(alignment.mate.chr);
|
|
49879
|
+
} else if (this.parent.minTemplateLength && Math.abs(alignment.fragmentLength) < this.parent.minTemplateLength) {
|
|
49880
|
+
color = this.smallTLENColor;
|
|
49881
|
+
} else if (this.parent.maxTemplateLength && Math.abs(alignment.fragmentLength) > this.parent.maxTemplateLength) {
|
|
49882
|
+
color = this.largeTLENColor;
|
|
49883
|
+
}
|
|
49901
49884
|
}
|
|
49902
49885
|
|
|
49903
49886
|
break;
|
|
@@ -49939,10 +49922,7 @@
|
|
|
49939
49922
|
alignmentContainer.packedAlignmentRows.sort(function (rowA, rowB) {
|
|
49940
49923
|
const i = rowA.score > rowB.score ? 1 : rowA.score < rowB.score ? -1 : 0;
|
|
49941
49924
|
return true === direction ? i : -i;
|
|
49942
|
-
});
|
|
49943
|
-
// for(let r of alignmentContainer.packedAlignmentRows) {
|
|
49944
|
-
// console.log(r.score);
|
|
49945
|
-
// }
|
|
49925
|
+
});
|
|
49946
49926
|
}
|
|
49947
49927
|
|
|
49948
49928
|
function shadedBaseColor(qual, baseColor) {
|
|
@@ -50097,7 +50077,7 @@
|
|
|
50097
50077
|
});
|
|
50098
50078
|
this.$viewport.append(this.$rulerLabel);
|
|
50099
50079
|
this.$rulerLabel.click(async () => {
|
|
50100
|
-
await this.browser.
|
|
50080
|
+
await this.browser.gotoMultilocusPanel(this.referenceFrame); // const removals = this.browser.referenceFrameList.filter(r => this.referenceFrame !== r)
|
|
50101
50081
|
// for (let referenceFrame of removals) {
|
|
50102
50082
|
// await this.browser.removeMultiLocusPanel(referenceFrame)
|
|
50103
50083
|
// }
|
|
@@ -50203,7 +50183,10 @@
|
|
|
50203
50183
|
currentViewport = this;
|
|
50204
50184
|
this.$tooltip.show();
|
|
50205
50185
|
} else if (currentViewport.guid !== this.guid) {
|
|
50206
|
-
currentViewport.$tooltip
|
|
50186
|
+
if (currentViewport.$tooltip) {
|
|
50187
|
+
currentViewport.$tooltip.hide();
|
|
50188
|
+
}
|
|
50189
|
+
|
|
50207
50190
|
this.$tooltip.show();
|
|
50208
50191
|
currentViewport = this;
|
|
50209
50192
|
} else {
|
|
@@ -50237,7 +50220,9 @@
|
|
|
50237
50220
|
}); // hide tooltip when movement stops
|
|
50238
50221
|
|
|
50239
50222
|
clearTimeout(timer);
|
|
50240
|
-
timer = setTimeout(() =>
|
|
50223
|
+
timer = setTimeout(() => {
|
|
50224
|
+
if (this.$tooltip) this.$tooltip.hide();
|
|
50225
|
+
}, toolTipTimeout);
|
|
50241
50226
|
}
|
|
50242
50227
|
}
|
|
50243
50228
|
|
|
@@ -50252,65 +50237,6 @@
|
|
|
50252
50237
|
|
|
50253
50238
|
}
|
|
50254
50239
|
|
|
50255
|
-
const viewportColumnManager = {
|
|
50256
|
-
createColumns: (columnContainer, count) => {
|
|
50257
|
-
for (let i = 0; i < count; i++) {
|
|
50258
|
-
if (0 === i) {
|
|
50259
|
-
createColumn(columnContainer, 'igv-column');
|
|
50260
|
-
} else {
|
|
50261
|
-
columnContainer.appendChild(div$1({
|
|
50262
|
-
class: 'igv-column-shim'
|
|
50263
|
-
}));
|
|
50264
|
-
createColumn(columnContainer, 'igv-column');
|
|
50265
|
-
}
|
|
50266
|
-
}
|
|
50267
|
-
},
|
|
50268
|
-
removeColumnAtIndex: (i, column) => {
|
|
50269
|
-
const shim = 0 === i ? column.nextElementSibling : column.previousElementSibling;
|
|
50270
|
-
column.remove();
|
|
50271
|
-
shim.remove();
|
|
50272
|
-
},
|
|
50273
|
-
insertAfter: referenceElement => {
|
|
50274
|
-
const shim = div$1({
|
|
50275
|
-
class: 'igv-column-shim'
|
|
50276
|
-
});
|
|
50277
|
-
insertElementAfter(shim, referenceElement);
|
|
50278
|
-
const column = div$1({
|
|
50279
|
-
class: 'igv-column'
|
|
50280
|
-
});
|
|
50281
|
-
insertElementAfter(column, shim);
|
|
50282
|
-
return column;
|
|
50283
|
-
},
|
|
50284
|
-
insertBefore: (referenceElement, count) => {
|
|
50285
|
-
for (let i = 0; i < count; i++) {
|
|
50286
|
-
const column = div$1({
|
|
50287
|
-
class: 'igv-column'
|
|
50288
|
-
});
|
|
50289
|
-
insertElementBefore(column, referenceElement);
|
|
50290
|
-
|
|
50291
|
-
if (count > 1 && i > 0) {
|
|
50292
|
-
const columnShim = div$1({
|
|
50293
|
-
class: 'igv-column-shim'
|
|
50294
|
-
});
|
|
50295
|
-
insertElementBefore(columnShim, column);
|
|
50296
|
-
}
|
|
50297
|
-
}
|
|
50298
|
-
},
|
|
50299
|
-
indexOfColumn: (columnContainer, column) => {
|
|
50300
|
-
const allColumns = columnContainer.querySelectorAll('.igv-column');
|
|
50301
|
-
|
|
50302
|
-
for (let i = 0; i < allColumns.length; i++) {
|
|
50303
|
-
const c = allColumns[i];
|
|
50304
|
-
|
|
50305
|
-
if (c === column) {
|
|
50306
|
-
return i;
|
|
50307
|
-
}
|
|
50308
|
-
}
|
|
50309
|
-
|
|
50310
|
-
return undefined;
|
|
50311
|
-
}
|
|
50312
|
-
};
|
|
50313
|
-
|
|
50314
50240
|
/*
|
|
50315
50241
|
* The MIT License (MIT)
|
|
50316
50242
|
*
|
|
@@ -50342,60 +50268,30 @@
|
|
|
50342
50268
|
}
|
|
50343
50269
|
|
|
50344
50270
|
initializationHelper() {
|
|
50345
|
-
this
|
|
50346
|
-
|
|
50347
|
-
|
|
50348
|
-
this
|
|
50349
|
-
const canvas = this.$ideogramCanvas.get(0);
|
|
50350
|
-
this.ideogram_ctx = canvas.getContext('2d');
|
|
50351
|
-
this.$canvas.remove();
|
|
50352
|
-
this.canvas = undefined;
|
|
50353
|
-
this.ctx = undefined;
|
|
50271
|
+
this.canvas = document.createElement('canvas');
|
|
50272
|
+
this.canvas.className = 'igv-ideogram-canvas';
|
|
50273
|
+
this.$content.append($$1(this.canvas));
|
|
50274
|
+
this.ideogram_ctx = this.canvas.getContext('2d');
|
|
50354
50275
|
this.addMouseHandlers();
|
|
50355
50276
|
}
|
|
50356
50277
|
|
|
50357
50278
|
addMouseHandlers() {
|
|
50358
|
-
this.addBrowserObserver();
|
|
50359
50279
|
this.addViewportClickHandler(this.$viewport.get(0));
|
|
50360
50280
|
}
|
|
50361
50281
|
|
|
50362
|
-
removeMouseHandlers() {
|
|
50363
|
-
this.removeBrowserObserver();
|
|
50364
|
-
this.removeViewportClickHandler(this.$viewport.get(0));
|
|
50365
|
-
}
|
|
50366
|
-
|
|
50367
|
-
addBrowserObserver() {
|
|
50368
|
-
function observerHandler(referenceFrameList) {
|
|
50369
|
-
const column = this.$viewport.get(0).parentElement;
|
|
50370
|
-
|
|
50371
|
-
if (null !== column) {
|
|
50372
|
-
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column); // console.log(`ideogram-viewport - locus-change-handler index(${ index }) ${ referenceFrameList[ index ].getLocusString() } ${ Date.now() } `)
|
|
50373
|
-
|
|
50374
|
-
this.update(this.ideogram_ctx, this.$viewport.width(), this.$viewport.height(), referenceFrameList[index]);
|
|
50375
|
-
}
|
|
50376
|
-
}
|
|
50377
|
-
|
|
50378
|
-
this.boundObserverHandler = observerHandler.bind(this);
|
|
50379
|
-
this.browser.on('locuschange', this.boundObserverHandler);
|
|
50380
|
-
}
|
|
50381
|
-
|
|
50382
|
-
removeBrowserObserver() {
|
|
50383
|
-
this.browser.off('locuschange', this.boundObserverHandler);
|
|
50384
|
-
}
|
|
50385
|
-
|
|
50386
50282
|
addViewportClickHandler(viewport) {
|
|
50283
|
+
this.boundClickHandler = clickHandler.bind(this);
|
|
50284
|
+
viewport.addEventListener('click', this.boundClickHandler);
|
|
50285
|
+
|
|
50387
50286
|
function clickHandler(event) {
|
|
50388
|
-
const column = viewport.parentElement;
|
|
50389
|
-
const index = viewportColumnManager.indexOfColumn(this.browser.columnContainer, column);
|
|
50390
|
-
const referenceFrame = this.browser.referenceFrameList[index];
|
|
50391
50287
|
const {
|
|
50392
50288
|
xNormalized,
|
|
50393
50289
|
width
|
|
50394
50290
|
} = translateMouseCoordinates$1(event, this.ideogram_ctx.canvas);
|
|
50395
50291
|
const {
|
|
50396
50292
|
bpLength
|
|
50397
|
-
} = this.browser.genome.getChromosome(referenceFrame.chr);
|
|
50398
|
-
const locusLength = referenceFrame.bpPerPixel * width;
|
|
50293
|
+
} = this.browser.genome.getChromosome(this.referenceFrame.chr);
|
|
50294
|
+
const locusLength = this.referenceFrame.bpPerPixel * width;
|
|
50399
50295
|
const chrCoveragePercentage = locusLength / bpLength;
|
|
50400
50296
|
let xPercentage = xNormalized;
|
|
50401
50297
|
|
|
@@ -50409,18 +50305,11 @@
|
|
|
50409
50305
|
|
|
50410
50306
|
const ss = Math.round((xPercentage - chrCoveragePercentage / 2.0) * bpLength);
|
|
50411
50307
|
const ee = Math.round((xPercentage + chrCoveragePercentage / 2.0) * bpLength);
|
|
50412
|
-
referenceFrame.start = ss;
|
|
50413
|
-
referenceFrame.end = ee;
|
|
50414
|
-
referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
50415
|
-
this.browser.updateViews(referenceFrame, this.browser.trackViews, true);
|
|
50308
|
+
this.referenceFrame.start = ss;
|
|
50309
|
+
this.referenceFrame.end = ee;
|
|
50310
|
+
this.referenceFrame.bpPerPixel = (ee - ss) / width;
|
|
50311
|
+
this.browser.updateViews(this.referenceFrame, this.browser.trackViews, true);
|
|
50416
50312
|
}
|
|
50417
|
-
|
|
50418
|
-
this.boundClickHandler = clickHandler.bind(this);
|
|
50419
|
-
viewport.addEventListener('click', this.boundClickHandler);
|
|
50420
|
-
}
|
|
50421
|
-
|
|
50422
|
-
removeViewportClickHandler(viewport) {
|
|
50423
|
-
viewport.removeEventListener('click', this.boundClickHandler);
|
|
50424
50313
|
}
|
|
50425
50314
|
|
|
50426
50315
|
setWidth(width) {
|
|
@@ -50438,14 +50327,22 @@
|
|
|
50438
50327
|
context.restore();
|
|
50439
50328
|
}
|
|
50440
50329
|
|
|
50441
|
-
|
|
50442
|
-
this
|
|
50443
|
-
|
|
50330
|
+
repaint() {
|
|
50331
|
+
this.draw({
|
|
50332
|
+
referenceFrame: this.referenceFrame
|
|
50333
|
+
});
|
|
50334
|
+
}
|
|
50335
|
+
|
|
50336
|
+
draw(_ref) {
|
|
50337
|
+
let {
|
|
50338
|
+
referenceFrame
|
|
50339
|
+
} = _ref;
|
|
50340
|
+
IGVGraphics.configureHighDPICanvas(this.ideogram_ctx, this.$viewport.width(), this.$viewport.height());
|
|
50444
50341
|
this.trackView.track.draw({
|
|
50445
|
-
context,
|
|
50342
|
+
context: this.ideogram_ctx,
|
|
50446
50343
|
referenceFrame,
|
|
50447
|
-
pixelWidth,
|
|
50448
|
-
pixelHeight
|
|
50344
|
+
pixelWidth: this.$viewport.width(),
|
|
50345
|
+
pixelHeight: this.$viewport.height()
|
|
50449
50346
|
});
|
|
50450
50347
|
}
|
|
50451
50348
|
|
|
@@ -50483,7 +50380,7 @@
|
|
|
50483
50380
|
function createViewport(trackView, column, referenceFrame, width) {
|
|
50484
50381
|
if ('ruler' === trackView.track.type) {
|
|
50485
50382
|
return new RulerViewport(trackView, column, referenceFrame, width);
|
|
50486
|
-
} else if ('ideogram' === trackView.track.
|
|
50383
|
+
} else if ('ideogram' === trackView.track.id) {
|
|
50487
50384
|
return new IdeogramViewport(trackView, column, referenceFrame, width);
|
|
50488
50385
|
} else {
|
|
50489
50386
|
return new TrackViewport(trackView, column, referenceFrame, width);
|
|
@@ -51010,7 +50907,6 @@
|
|
|
51010
50907
|
|
|
51011
50908
|
class TrackView {
|
|
51012
50909
|
constructor(browser, columnContainer, track) {
|
|
51013
|
-
this.namespace = `trackview-${guid$2()}`;
|
|
51014
50910
|
this.browser = browser;
|
|
51015
50911
|
this.track = track;
|
|
51016
50912
|
track.trackView = this;
|
|
@@ -51036,7 +50932,7 @@
|
|
|
51036
50932
|
|
|
51037
50933
|
addDOMToColumnContainer(browser, columnContainer, referenceFrameList) {
|
|
51038
50934
|
// Axis
|
|
51039
|
-
this.axis = this.createAxis(browser, this.track); //
|
|
50935
|
+
this.axis = this.createAxis(browser, this.track); // Create a viewport for each reference frame
|
|
51040
50936
|
|
|
51041
50937
|
this.viewports = [];
|
|
51042
50938
|
const viewportWidth = browser.calculateViewportWidth(referenceFrameList.length);
|
|
@@ -51103,7 +50999,6 @@
|
|
|
51103
50999
|
this.axis.remove(); // Track Viewports
|
|
51104
51000
|
|
|
51105
51001
|
for (let viewport of this.viewports) {
|
|
51106
|
-
viewport.removeMouseHandlers();
|
|
51107
51002
|
viewport.$viewport.remove();
|
|
51108
51003
|
} // SampleName Viewport
|
|
51109
51004
|
|
|
@@ -51221,7 +51116,7 @@
|
|
|
51221
51116
|
$viewport.height(newHeight);
|
|
51222
51117
|
}
|
|
51223
51118
|
|
|
51224
|
-
this.sampleNameViewport.viewport.style.height = `${newHeight}px`; // If the track does not manage its own content height set it here
|
|
51119
|
+
this.sampleNameViewport.viewport.style.height = `${newHeight}px`; // If the track does not manage its own content height set it equal to the viewport height here
|
|
51225
51120
|
|
|
51226
51121
|
if (typeof this.track.computePixelHeight !== "function") {
|
|
51227
51122
|
for (let vp of this.viewports) {
|
|
@@ -51273,14 +51168,6 @@
|
|
|
51273
51168
|
if (viewport.isLoading()) return true;
|
|
51274
51169
|
}
|
|
51275
51170
|
}
|
|
51276
|
-
|
|
51277
|
-
resize(viewportWidth) {
|
|
51278
|
-
for (let viewport of this.viewports) {
|
|
51279
|
-
viewport.setWidth(viewportWidth);
|
|
51280
|
-
}
|
|
51281
|
-
|
|
51282
|
-
this.updateViews(true);
|
|
51283
|
-
}
|
|
51284
51171
|
/**
|
|
51285
51172
|
* Repaint all viewports without loading any new data. Use this for events that change visual aspect of data,
|
|
51286
51173
|
* e.g. color, sort order, etc, but do not change the genomic state.
|
|
@@ -51289,7 +51176,9 @@
|
|
|
51289
51176
|
|
|
51290
51177
|
repaintViews() {
|
|
51291
51178
|
for (let viewport of this.viewports) {
|
|
51292
|
-
viewport.
|
|
51179
|
+
if (viewport.isVisible()) {
|
|
51180
|
+
viewport.repaint();
|
|
51181
|
+
}
|
|
51293
51182
|
}
|
|
51294
51183
|
|
|
51295
51184
|
if (typeof this.track.paintAxis === 'function') {
|
|
@@ -51311,41 +51200,60 @@
|
|
|
51311
51200
|
setTrackLabelName(name) {
|
|
51312
51201
|
this.viewports.forEach(viewport => viewport.setTrackLabel(name));
|
|
51313
51202
|
}
|
|
51203
|
+
/**
|
|
51204
|
+
* Called in response to a window resize event, change in # of multilocus panels, or other event that changes
|
|
51205
|
+
* the width of the track view.
|
|
51206
|
+
*
|
|
51207
|
+
* @param viewportWidth The width of each viewport in this track view.
|
|
51208
|
+
*/
|
|
51209
|
+
|
|
51210
|
+
|
|
51211
|
+
resize(viewportWidth) {
|
|
51212
|
+
for (let viewport of this.viewports) {
|
|
51213
|
+
viewport.setWidth(viewportWidth);
|
|
51214
|
+
}
|
|
51215
|
+
}
|
|
51314
51216
|
/**
|
|
51315
51217
|
* Update viewports to reflect current genomic state, possibly loading additional data.
|
|
51218
|
+
*
|
|
51219
|
+
* @param force - if true, force a repaint even if no new data is loaded
|
|
51220
|
+
* @returns {Promise<void>}
|
|
51316
51221
|
*/
|
|
51317
51222
|
|
|
51318
51223
|
|
|
51319
|
-
async updateViews(
|
|
51224
|
+
async updateViews() {
|
|
51320
51225
|
if (!(this.browser && this.browser.referenceFrameList)) return;
|
|
51321
51226
|
const visibleViewports = this.viewports.filter(viewport => viewport.isVisible()); // Shift viewports left/right to current genomic state (pans canvas)
|
|
51322
51227
|
|
|
51323
|
-
visibleViewports.forEach(viewport => viewport.shift());
|
|
51324
|
-
const isDragging = this.browser.dragObject;
|
|
51228
|
+
visibleViewports.forEach(viewport => viewport.shift()); // If dragging (panning) return
|
|
51325
51229
|
|
|
51326
|
-
if (
|
|
51230
|
+
if (this.browser.dragObject) {
|
|
51327
51231
|
return;
|
|
51328
|
-
} //
|
|
51232
|
+
} // Get viewports to repaint
|
|
51233
|
+
|
|
51329
51234
|
|
|
51235
|
+
let viewportsToRepaint = this.track.autoscale || this.track.autoscaleGroup || this.track.type === 'ruler' ? visibleViewports : visibleViewports.filter(vp => vp.needsRepaint()); // Filter zoomed out views. This has the side effect or turning off or no the zoomed out notice
|
|
51330
51236
|
|
|
51331
|
-
|
|
51237
|
+
viewportsToRepaint = viewportsToRepaint.filter(viewport => viewport.checkZoomIn()); // Get viewports that require a data load
|
|
51238
|
+
|
|
51239
|
+
const viewportsToReload = viewportsToRepaint.filter(viewport => viewport.needsReload()); // Trigger viewport to load features needed to cover current genomic range
|
|
51332
51240
|
// NOTE: these must be loaded synchronously, do not user Promise.all, not all file readers are thread safe
|
|
51333
51241
|
|
|
51334
|
-
for (let viewport of
|
|
51242
|
+
for (let viewport of viewportsToReload) {
|
|
51335
51243
|
await viewport.loadFeatures();
|
|
51336
51244
|
}
|
|
51337
51245
|
|
|
51338
51246
|
if (this.disposed) return; // Track was removed during load
|
|
51339
|
-
//
|
|
51247
|
+
// Special case for variant tracks in multilocus view. The # of rows to allocate to the variant (site)
|
|
51340
51248
|
// section depends on data from all the views. We only need to adjust this however if any data was loaded
|
|
51341
51249
|
// (i.e. reloadableViewports.length > 0)
|
|
51342
51250
|
|
|
51343
|
-
if (this.track && typeof this.track.variantRowCount === 'function' &&
|
|
51251
|
+
if (this.track && typeof this.track.variantRowCount === 'function' && viewportsToReload.length > 0) {
|
|
51344
51252
|
let maxRow = 0;
|
|
51345
51253
|
|
|
51346
51254
|
for (let viewport of this.viewports) {
|
|
51347
|
-
if (viewport.
|
|
51348
|
-
maxRow = Math.max(maxRow, viewport.
|
|
51255
|
+
if (viewport.featureCache && viewport.featureCache.features) {
|
|
51256
|
+
maxRow = Math.max(maxRow, viewport.featureCache.features.reduce((a, f) => Math.max(a, f.row || 0), 0));
|
|
51349
51257
|
}
|
|
51350
51258
|
}
|
|
51351
51259
|
|
|
@@ -51368,14 +51276,14 @@
|
|
|
51368
51276
|
const start = referenceFrame.start;
|
|
51369
51277
|
const end = start + referenceFrame.toBP($$1(visibleViewport.contentDiv).width());
|
|
51370
51278
|
|
|
51371
|
-
if (visibleViewport.
|
|
51372
|
-
if (typeof visibleViewport.
|
|
51373
|
-
const max = visibleViewport.
|
|
51279
|
+
if (visibleViewport.featureCache && visibleViewport.featureCache.features) {
|
|
51280
|
+
if (typeof visibleViewport.featureCache.features.getMax === 'function') {
|
|
51281
|
+
const max = visibleViewport.featureCache.features.getMax(start, end);
|
|
51374
51282
|
allFeatures.push({
|
|
51375
51283
|
value: max
|
|
51376
51284
|
});
|
|
51377
51285
|
} else {
|
|
51378
|
-
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(visibleViewport.
|
|
51286
|
+
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(visibleViewport.featureCache.features, start, end));
|
|
51379
51287
|
}
|
|
51380
51288
|
}
|
|
51381
51289
|
}
|
|
@@ -51385,17 +51293,10 @@
|
|
|
51385
51293
|
} else {
|
|
51386
51294
|
this.track.dataRange = doAutoscale(allFeatures);
|
|
51387
51295
|
}
|
|
51388
|
-
}
|
|
51389
|
-
|
|
51296
|
+
}
|
|
51390
51297
|
|
|
51391
|
-
|
|
51392
|
-
|
|
51393
|
-
visibleViewport.repaint();
|
|
51394
|
-
}
|
|
51395
|
-
} else {
|
|
51396
|
-
for (let vp of reloadableViewports) {
|
|
51397
|
-
vp.repaint();
|
|
51398
|
-
}
|
|
51298
|
+
for (let vp of viewportsToRepaint) {
|
|
51299
|
+
vp.repaint();
|
|
51399
51300
|
}
|
|
51400
51301
|
|
|
51401
51302
|
this.adjustTrackHeight(); // Repaint sample names last
|
|
@@ -51418,36 +51319,34 @@
|
|
|
51418
51319
|
}
|
|
51419
51320
|
}
|
|
51420
51321
|
/**
|
|
51421
|
-
* Return a promise to get all in-view features. Used for group autoscaling.
|
|
51322
|
+
* Return a promise to get all in-view features across all viewports. Used for group autoscaling.
|
|
51422
51323
|
*/
|
|
51423
51324
|
|
|
51424
51325
|
|
|
51425
|
-
async getInViewFeatures(
|
|
51326
|
+
async getInViewFeatures() {
|
|
51426
51327
|
if (!(this.browser && this.browser.referenceFrameList)) {
|
|
51427
51328
|
return [];
|
|
51428
|
-
}
|
|
51429
|
-
|
|
51329
|
+
}
|
|
51430
51330
|
|
|
51431
|
-
const rpV = this.viewportsToReload(force);
|
|
51432
|
-
const promises = rpV.map(function (vp) {
|
|
51433
|
-
return vp.loadFeatures();
|
|
51434
|
-
});
|
|
51435
|
-
await Promise.all(promises);
|
|
51436
51331
|
let allFeatures = [];
|
|
51437
51332
|
|
|
51438
51333
|
for (let vp of this.viewports) {
|
|
51439
|
-
if (vp.
|
|
51334
|
+
if (vp.needsReload()) {
|
|
51335
|
+
await vp.loadFeatures();
|
|
51336
|
+
}
|
|
51337
|
+
|
|
51338
|
+
if (vp.featureCache && vp.featureCache.features) {
|
|
51440
51339
|
const referenceFrame = vp.referenceFrame;
|
|
51441
51340
|
const start = referenceFrame.start;
|
|
51442
51341
|
const end = start + referenceFrame.toBP($$1(vp.contentDiv).width());
|
|
51443
51342
|
|
|
51444
|
-
if (typeof vp.
|
|
51445
|
-
const max = vp.
|
|
51343
|
+
if (typeof vp.featureCache.features.getMax === 'function') {
|
|
51344
|
+
const max = vp.featureCache.features.getMax(start, end);
|
|
51446
51345
|
allFeatures.push({
|
|
51447
51346
|
value: max
|
|
51448
51347
|
});
|
|
51449
51348
|
} else {
|
|
51450
|
-
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(vp.
|
|
51349
|
+
allFeatures = allFeatures.concat(FeatureUtils.findOverlapping(vp.featureCache.features, start, end));
|
|
51451
51350
|
}
|
|
51452
51351
|
}
|
|
51453
51352
|
}
|
|
@@ -51489,27 +51388,6 @@
|
|
|
51489
51388
|
}
|
|
51490
51389
|
}
|
|
51491
51390
|
|
|
51492
|
-
viewportsToReload(force) {
|
|
51493
|
-
// List of viewports that need reloading
|
|
51494
|
-
const viewports = this.viewports.filter(viewport => {
|
|
51495
|
-
if (!viewport.isVisible()) {
|
|
51496
|
-
return false;
|
|
51497
|
-
}
|
|
51498
|
-
|
|
51499
|
-
if (!viewport.checkZoomIn()) {
|
|
51500
|
-
return false;
|
|
51501
|
-
} else {
|
|
51502
|
-
const referenceFrame = viewport.referenceFrame;
|
|
51503
|
-
const chr = viewport.referenceFrame.chr;
|
|
51504
|
-
const start = referenceFrame.start;
|
|
51505
|
-
const end = start + referenceFrame.toBP($$1(viewport.contentDiv).width());
|
|
51506
|
-
const bpPerPixel = referenceFrame.bpPerPixel;
|
|
51507
|
-
return force || !viewport.tile || viewport.tile.invalidate || !viewport.tile.containsRange(chr, start, end, bpPerPixel);
|
|
51508
|
-
}
|
|
51509
|
-
});
|
|
51510
|
-
return viewports;
|
|
51511
|
-
}
|
|
51512
|
-
|
|
51513
51391
|
createTrackScrollbar(browser) {
|
|
51514
51392
|
const outerScroll = div$1();
|
|
51515
51393
|
browser.columnContainer.querySelector('.igv-scrollbar-column').appendChild(outerScroll);
|
|
@@ -51603,7 +51481,7 @@
|
|
|
51603
51481
|
}
|
|
51604
51482
|
|
|
51605
51483
|
addTrackDragMouseHandlers(browser) {
|
|
51606
|
-
if ('ideogram' === this.track.
|
|
51484
|
+
if ('ideogram' === this.track.id || 'ruler' === this.track.id) ; else {
|
|
51607
51485
|
let currentDragHandle = undefined; // Mouse Down
|
|
51608
51486
|
|
|
51609
51487
|
this.boundTrackDragMouseDownHandler = trackDragMouseDownHandler.bind(this);
|
|
@@ -51667,7 +51545,7 @@
|
|
|
51667
51545
|
}
|
|
51668
51546
|
|
|
51669
51547
|
removeTrackDragMouseHandlers() {
|
|
51670
|
-
if ('ideogram' === this.track.
|
|
51548
|
+
if ('ideogram' === this.track.id || 'ruler' === this.track.id) ; else {
|
|
51671
51549
|
this.dragHandle.removeEventListener('mousedown', this.boundTrackDragMouseDownHandler);
|
|
51672
51550
|
document.removeEventListener('mouseup', this.boundDocumentTrackDragMouseUpHandler);
|
|
51673
51551
|
this.dragHandle.removeEventListener('mouseup', this.boundTrackDragMouseEnterHandler);
|
|
@@ -56314,7 +56192,7 @@
|
|
|
56314
56192
|
this.genome = genome;
|
|
56315
56193
|
this.sourceType = config.sourceType === undefined ? "file" : config.sourceType;
|
|
56316
56194
|
this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
|
|
56317
|
-
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "tdf"]);
|
|
56195
|
+
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "tdf"]);
|
|
56318
56196
|
|
|
56319
56197
|
if (config.features && Array.isArray(config.features)) {
|
|
56320
56198
|
// Explicit array of features
|
|
@@ -56326,7 +56204,7 @@
|
|
|
56326
56204
|
}
|
|
56327
56205
|
|
|
56328
56206
|
this.queryable = false;
|
|
56329
|
-
this.featureCache = new FeatureCache(features, genome);
|
|
56207
|
+
this.featureCache = new FeatureCache$1(features, genome);
|
|
56330
56208
|
} else if (config.reader) {
|
|
56331
56209
|
// Explicit reader implementation
|
|
56332
56210
|
this.reader = config.reader;
|
|
@@ -56497,13 +56375,13 @@
|
|
|
56497
56375
|
} // Note - replacing previous cache with new one. genomicInterval is optional (might be undefined => includes all features)
|
|
56498
56376
|
|
|
56499
56377
|
|
|
56500
|
-
this.featureCache = new FeatureCache(features, this.genome, genomicInterval); // If track is marked "searchable"< cache features by name -- use this with caution, memory intensive
|
|
56378
|
+
this.featureCache = new FeatureCache$1(features, this.genome, genomicInterval); // If track is marked "searchable"< cache features by name -- use this with caution, memory intensive
|
|
56501
56379
|
|
|
56502
56380
|
if (this.config.searchable || this.config.searchableFields) {
|
|
56503
56381
|
this.addFeaturesToDB(features);
|
|
56504
56382
|
}
|
|
56505
56383
|
} else {
|
|
56506
|
-
this.featureCache = new FeatureCache([], genomicInterval); // Empty cache
|
|
56384
|
+
this.featureCache = new FeatureCache$1([], genomicInterval); // Empty cache
|
|
56507
56385
|
}
|
|
56508
56386
|
}
|
|
56509
56387
|
|
|
@@ -56727,8 +56605,8 @@
|
|
|
56727
56605
|
|
|
56728
56606
|
//table chromatinInteract
|
|
56729
56607
|
|
|
56730
|
-
function getDecoder(definedFieldCount, fieldCount, autoSql) {
|
|
56731
|
-
if (autoSql && 'chromatinInteract' === autoSql.table) {
|
|
56608
|
+
function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
|
|
56609
|
+
if (autoSql && 'chromatinInteract' === autoSql.table || "biginteract" === format) {
|
|
56732
56610
|
return decodeInteract;
|
|
56733
56611
|
} else {
|
|
56734
56612
|
const standardFieldCount = definedFieldCount - 3;
|
|
@@ -56863,6 +56741,7 @@
|
|
|
56863
56741
|
class BWReader {
|
|
56864
56742
|
constructor(config, genome) {
|
|
56865
56743
|
this.path = config.url;
|
|
56744
|
+
this.format = config.format || "bigwig";
|
|
56866
56745
|
this.genome = genome;
|
|
56867
56746
|
this.rpTreeCache = {};
|
|
56868
56747
|
this.config = config;
|
|
@@ -57441,7 +57320,7 @@
|
|
|
57441
57320
|
function getBedDataDecoder() {
|
|
57442
57321
|
const minSize = 3 * 4 + 1; // Minimum # of bytes required for a bed record
|
|
57443
57322
|
|
|
57444
|
-
const decoder = getDecoder(this.header.definedFieldCount, this.header.fieldCount, this.autoSql);
|
|
57323
|
+
const decoder = getDecoder(this.header.definedFieldCount, this.header.fieldCount, this.autoSql, this.format);
|
|
57445
57324
|
return function (data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, chrDict) {
|
|
57446
57325
|
const binaryParser = new BinaryParser(data);
|
|
57447
57326
|
|
|
@@ -58252,7 +58131,7 @@
|
|
|
58252
58131
|
return features;
|
|
58253
58132
|
}
|
|
58254
58133
|
|
|
58255
|
-
supportsWholeGenome() {
|
|
58134
|
+
get supportsWholeGenome() {
|
|
58256
58135
|
return true;
|
|
58257
58136
|
}
|
|
58258
58137
|
|
|
@@ -58361,7 +58240,7 @@
|
|
|
58361
58240
|
function FeatureSource(config, genome) {
|
|
58362
58241
|
const format = config.format ? config.format.toLowerCase() : undefined;
|
|
58363
58242
|
|
|
58364
|
-
if ('bigwig' === format || 'bigbed' === format || 'bb' === format) {
|
|
58243
|
+
if ('bigwig' === format || 'bigbed' === format || 'bb' === format || "biginteract" === format) {
|
|
58365
58244
|
return new BWSource(config, genome);
|
|
58366
58245
|
} else if ("tdf" === format) {
|
|
58367
58246
|
return new TDFSource(config, genome);
|
|
@@ -58370,30 +58249,6 @@
|
|
|
58370
58249
|
}
|
|
58371
58250
|
}
|
|
58372
58251
|
|
|
58373
|
-
const pairs = [['A', 'T'], ['G', 'C'], ['Y', 'R'], ['W', 'S'], ['K', 'M'], ['D', 'H'], ['B', 'V']];
|
|
58374
|
-
const complements = new Map();
|
|
58375
|
-
|
|
58376
|
-
for (let p of pairs) {
|
|
58377
|
-
const p1 = p[0];
|
|
58378
|
-
const p2 = p[1];
|
|
58379
|
-
complements.set(p1, p2);
|
|
58380
|
-
complements.set(p2, p1);
|
|
58381
|
-
complements.set(p1.toLowerCase(), p2.toLowerCase());
|
|
58382
|
-
complements.set(p2.toLowerCase(), p1.toLowerCase());
|
|
58383
|
-
}
|
|
58384
|
-
|
|
58385
|
-
function reverseComplementSequence(sequence) {
|
|
58386
|
-
let comp = '';
|
|
58387
|
-
let idx = sequence.length;
|
|
58388
|
-
|
|
58389
|
-
while (idx-- > 0) {
|
|
58390
|
-
const base = sequence[idx];
|
|
58391
|
-
comp += complements.has(base) ? complements.get(base) : base;
|
|
58392
|
-
}
|
|
58393
|
-
|
|
58394
|
-
return comp;
|
|
58395
|
-
}
|
|
58396
|
-
|
|
58397
58252
|
const GtexUtils = {
|
|
58398
58253
|
getTissueInfo: function (datasetId, baseURL) {
|
|
58399
58254
|
datasetId = datasetId || 'gtex_v8';
|
|
@@ -58489,7 +58344,7 @@
|
|
|
58489
58344
|
// single-exon transcript
|
|
58490
58345
|
const xLeft = Math.max(0, coord.px);
|
|
58491
58346
|
const xRight = Math.min(pixelWidth, coord.px1);
|
|
58492
|
-
const width =
|
|
58347
|
+
const width = xRight - xLeft;
|
|
58493
58348
|
ctx.fillRect(xLeft, py, width, h); // Arrows
|
|
58494
58349
|
// Do not draw if strand is not +/-
|
|
58495
58350
|
|
|
@@ -58916,7 +58771,7 @@
|
|
|
58916
58771
|
return this;
|
|
58917
58772
|
}
|
|
58918
58773
|
|
|
58919
|
-
supportsWholeGenome() {
|
|
58774
|
+
get supportsWholeGenome() {
|
|
58920
58775
|
return (this.config.indexed === false || !this.config.indexURL) && this.config.supportsWholeGenome !== false;
|
|
58921
58776
|
}
|
|
58922
58777
|
|
|
@@ -59069,15 +58924,9 @@
|
|
|
59069
58924
|
for (let fd of featureData) {
|
|
59070
58925
|
data.push(fd);
|
|
59071
58926
|
|
|
59072
|
-
if (infoURL) {
|
|
59073
|
-
|
|
59074
|
-
|
|
59075
|
-
const href = url.replace("$$", feature.name);
|
|
59076
|
-
data.push({
|
|
59077
|
-
name: "Info",
|
|
59078
|
-
value: `<a target="_blank" href=${href}>${fd.value}</a>`
|
|
59079
|
-
});
|
|
59080
|
-
}
|
|
58927
|
+
if (infoURL && fd.name && fd.name.toLowerCase() === "name" && fd.value && isString$3(fd.value) && !fd.value.startsWith("<")) {
|
|
58928
|
+
const href = infoURL.replace("$$", feature.name);
|
|
58929
|
+
fd.value = `<a target=_blank href=${href}>${fd.value}</a>`;
|
|
59081
58930
|
}
|
|
59082
58931
|
} //Array.prototype.push.apply(data, featureData);
|
|
59083
58932
|
// If we have clicked over an exon number it.
|
|
@@ -59151,17 +59000,31 @@
|
|
|
59151
59000
|
}
|
|
59152
59001
|
|
|
59153
59002
|
contextMenuItemList(clickState) {
|
|
59154
|
-
|
|
59155
|
-
const features = this.clickedFeatures(clickState);
|
|
59003
|
+
const features = this.clickedFeatures(clickState);
|
|
59156
59004
|
|
|
59157
|
-
|
|
59158
|
-
|
|
59159
|
-
|
|
59005
|
+
if (features.length > 1) {
|
|
59006
|
+
features.sort((a, b) => b.end - b.start - (a.end - a.start));
|
|
59007
|
+
}
|
|
59008
|
+
|
|
59009
|
+
const f = features[0]; // The shortest clicked feature
|
|
59010
|
+
|
|
59011
|
+
if (f.end - f.start <= 1000000) {
|
|
59012
|
+
const list = [{
|
|
59013
|
+
label: 'View feature sequence',
|
|
59014
|
+
click: async () => {
|
|
59015
|
+
let seq = await this.browser.genome.getSequence(f.chr, f.start, f.end);
|
|
59016
|
+
|
|
59017
|
+
if (f.strand === '-') {
|
|
59018
|
+
seq = reverseComplementSequence(seq);
|
|
59019
|
+
}
|
|
59160
59020
|
|
|
59161
|
-
|
|
59021
|
+
if (!seq) seq = "Unknown sequence";
|
|
59022
|
+
Alert.presentAlert(seq);
|
|
59023
|
+
}
|
|
59024
|
+
}];
|
|
59162
59025
|
|
|
59163
|
-
if (
|
|
59164
|
-
|
|
59026
|
+
if (isSecureContext() && navigator.clipboard !== undefined) {
|
|
59027
|
+
list.push({
|
|
59165
59028
|
label: 'Copy feature sequence',
|
|
59166
59029
|
click: async () => {
|
|
59167
59030
|
let seq = await this.browser.genome.getSequence(f.chr, f.start, f.end);
|
|
@@ -59170,14 +59033,21 @@
|
|
|
59170
59033
|
seq = reverseComplementSequence(seq);
|
|
59171
59034
|
}
|
|
59172
59035
|
|
|
59173
|
-
|
|
59036
|
+
try {
|
|
59037
|
+
await navigator.clipboard.writeText(seq);
|
|
59038
|
+
} catch (e) {
|
|
59039
|
+
console.error(e);
|
|
59040
|
+
Alert.presentAlert(`error copying sequence to clipboard ${e}`);
|
|
59041
|
+
}
|
|
59174
59042
|
}
|
|
59175
|
-
}
|
|
59043
|
+
});
|
|
59176
59044
|
}
|
|
59177
|
-
} // Either not a secure context (i.e. http: protocol), or feature is too long
|
|
59178
|
-
|
|
59179
59045
|
|
|
59180
|
-
|
|
59046
|
+
list.push('<hr/>');
|
|
59047
|
+
return list;
|
|
59048
|
+
} else {
|
|
59049
|
+
return undefined;
|
|
59050
|
+
}
|
|
59181
59051
|
}
|
|
59182
59052
|
|
|
59183
59053
|
description() {
|
|
@@ -59273,14 +59143,12 @@
|
|
|
59273
59143
|
this.featureType = 'numeric';
|
|
59274
59144
|
this.paintAxis = paintAxis;
|
|
59275
59145
|
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
59146
|
+
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59147
|
+
this.logScale = config.logScale ? config.logScale : false;
|
|
59276
59148
|
|
|
59277
59149
|
if ("bigwig" === format) {
|
|
59278
|
-
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59279
|
-
this.logScale = config.logScale ? config.logScale : false;
|
|
59280
59150
|
this.featureSource = new BWSource(config, this.browser.genome);
|
|
59281
59151
|
} else if ("tdf" === format) {
|
|
59282
|
-
this.flipAxis = config.flipAxis ? config.flipAxis : false;
|
|
59283
|
-
this.logScale = config.logScale ? config.logScale : false;
|
|
59284
59152
|
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
59285
59153
|
} else {
|
|
59286
59154
|
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
@@ -59518,7 +59386,7 @@
|
|
|
59518
59386
|
}
|
|
59519
59387
|
}
|
|
59520
59388
|
|
|
59521
|
-
supportsWholeGenome() {
|
|
59389
|
+
get supportsWholeGenome() {
|
|
59522
59390
|
return !this.config.indexURL && this.config.supportsWholeGenome !== false;
|
|
59523
59391
|
}
|
|
59524
59392
|
/**
|
|
@@ -60057,7 +59925,7 @@
|
|
|
60057
59925
|
|
|
60058
59926
|
const sortHandler = sort => {
|
|
60059
59927
|
const viewport = clickState.viewport;
|
|
60060
|
-
const features = viewport.
|
|
59928
|
+
const features = viewport.cachedFeatures;
|
|
60061
59929
|
this.sortSamples(sort.chr, sort.start, sort.end, sort.direction, features);
|
|
60062
59930
|
};
|
|
60063
59931
|
|
|
@@ -60077,7 +59945,7 @@
|
|
|
60077
59945
|
}];
|
|
60078
59946
|
}
|
|
60079
59947
|
|
|
60080
|
-
supportsWholeGenome() {
|
|
59948
|
+
get supportsWholeGenome() {
|
|
60081
59949
|
return (this.config.indexed === false || !this.config.indexURL) && this.config.supportsWholeGenome !== false;
|
|
60082
59950
|
}
|
|
60083
59951
|
|
|
@@ -60163,10 +60031,16 @@
|
|
|
60163
60031
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
60164
60032
|
* THE SOFTWARE.
|
|
60165
60033
|
*/
|
|
60034
|
+
/**
|
|
60035
|
+
* Represents 2 or more wig tracks overlaid on a common viewport.
|
|
60036
|
+
*/
|
|
60166
60037
|
|
|
60167
60038
|
class MergedTrack extends TrackBase {
|
|
60168
60039
|
constructor(config, browser) {
|
|
60169
60040
|
super(config, browser);
|
|
60041
|
+
this.type = "merged";
|
|
60042
|
+
this.featureType = 'numeric';
|
|
60043
|
+
this.paintAxis = paintAxis;
|
|
60170
60044
|
}
|
|
60171
60045
|
|
|
60172
60046
|
init(config) {
|
|
@@ -60177,21 +60051,6 @@
|
|
|
60177
60051
|
super.init(config);
|
|
60178
60052
|
}
|
|
60179
60053
|
|
|
60180
|
-
get height() {
|
|
60181
|
-
return this._height;
|
|
60182
|
-
}
|
|
60183
|
-
|
|
60184
|
-
set height(h) {
|
|
60185
|
-
this._height = h;
|
|
60186
|
-
|
|
60187
|
-
if (this.tracks) {
|
|
60188
|
-
for (let t of this.tracks) {
|
|
60189
|
-
t.height = h;
|
|
60190
|
-
t.config.height = h;
|
|
60191
|
-
}
|
|
60192
|
-
}
|
|
60193
|
-
}
|
|
60194
|
-
|
|
60195
60054
|
async postInit() {
|
|
60196
60055
|
this.tracks = [];
|
|
60197
60056
|
const p = [];
|
|
@@ -60213,45 +60072,83 @@
|
|
|
60213
60072
|
}
|
|
60214
60073
|
}
|
|
60215
60074
|
|
|
60216
|
-
this.
|
|
60075
|
+
this.flipAxis = this.config.flipAxis ? this.config.flipAxis : false;
|
|
60076
|
+
this.logScale = this.config.logScale ? this.config.logScale : false;
|
|
60077
|
+
this.autoscale = this.config.autoscale || this.config.max === undefined;
|
|
60078
|
+
|
|
60079
|
+
if (!this.autoscale) {
|
|
60080
|
+
this.dataRange = {
|
|
60081
|
+
min: this.config.min || 0,
|
|
60082
|
+
max: this.config.max
|
|
60083
|
+
};
|
|
60084
|
+
}
|
|
60085
|
+
|
|
60086
|
+
for (let t of this.tracks) {
|
|
60087
|
+
t.autoscale = false;
|
|
60088
|
+
t.dataRange = this.dataRange;
|
|
60089
|
+
}
|
|
60090
|
+
|
|
60091
|
+
this.height = this.config.height || 50;
|
|
60217
60092
|
return Promise.all(p);
|
|
60218
60093
|
}
|
|
60219
60094
|
|
|
60095
|
+
get height() {
|
|
60096
|
+
return this._height;
|
|
60097
|
+
}
|
|
60098
|
+
|
|
60099
|
+
set height(h) {
|
|
60100
|
+
this._height = h;
|
|
60101
|
+
|
|
60102
|
+
if (this.tracks) {
|
|
60103
|
+
for (let t of this.tracks) {
|
|
60104
|
+
t.height = h;
|
|
60105
|
+
t.config.height = h;
|
|
60106
|
+
}
|
|
60107
|
+
}
|
|
60108
|
+
}
|
|
60109
|
+
|
|
60110
|
+
menuItemList() {
|
|
60111
|
+
let items = [];
|
|
60112
|
+
|
|
60113
|
+
if (this.flipAxis !== undefined) {
|
|
60114
|
+
items.push({
|
|
60115
|
+
label: "Flip y-axis",
|
|
60116
|
+
click: () => {
|
|
60117
|
+
this.flipAxis = !this.flipAxis;
|
|
60118
|
+
this.trackView.repaintViews();
|
|
60119
|
+
}
|
|
60120
|
+
});
|
|
60121
|
+
}
|
|
60122
|
+
|
|
60123
|
+
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
60124
|
+
return items;
|
|
60125
|
+
}
|
|
60126
|
+
|
|
60220
60127
|
async getFeatures(chr, bpStart, bpEnd, bpPerPixel) {
|
|
60221
60128
|
const promises = this.tracks.map(t => t.getFeatures(chr, bpStart, bpEnd, bpPerPixel));
|
|
60222
60129
|
return Promise.all(promises);
|
|
60223
60130
|
}
|
|
60224
60131
|
|
|
60225
60132
|
draw(options) {
|
|
60226
|
-
|
|
60227
|
-
mergedFeatures = options.features; // Array of feature arrays, 1 for each track
|
|
60133
|
+
const mergedFeatures = options.features; // Array of feature arrays, 1 for each track
|
|
60228
60134
|
|
|
60229
|
-
|
|
60135
|
+
if (this.autoscale) {
|
|
60136
|
+
this.dataRange = autoscale(options.referenceFrame.chr, mergedFeatures);
|
|
60137
|
+
}
|
|
60230
60138
|
|
|
60231
|
-
for (i = 0, len = this.tracks.length; i < len; i++) {
|
|
60232
|
-
trackOptions = Object.assign({}, options);
|
|
60139
|
+
for (let i = 0, len = this.tracks.length; i < len; i++) {
|
|
60140
|
+
const trackOptions = Object.assign({}, options);
|
|
60233
60141
|
trackOptions.features = mergedFeatures[i];
|
|
60234
|
-
this.tracks[i].dataRange = dataRange;
|
|
60142
|
+
this.tracks[i].dataRange = this.dataRange;
|
|
60143
|
+
this.tracks[i].flipAxis = this.flipAxis;
|
|
60144
|
+
this.tracks[i].logScale = this.logScale;
|
|
60145
|
+
this.tracks[i].graphType = this.graphType;
|
|
60235
60146
|
this.tracks[i].draw(trackOptions);
|
|
60236
60147
|
}
|
|
60237
60148
|
}
|
|
60238
60149
|
|
|
60239
|
-
paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
60240
|
-
var i, len, autoscale, track;
|
|
60241
|
-
autoscale = true; // Hardcoded for now
|
|
60242
|
-
|
|
60243
|
-
for (i = 0, len = this.tracks.length; i < len; i++) {
|
|
60244
|
-
track = this.tracks[i];
|
|
60245
|
-
|
|
60246
|
-
if (typeof track.paintAxis === 'function') {
|
|
60247
|
-
track.paintAxis(ctx, pixelWidth, pixelHeight);
|
|
60248
|
-
if (autoscale) break;
|
|
60249
|
-
}
|
|
60250
|
-
}
|
|
60251
|
-
}
|
|
60252
|
-
|
|
60253
60150
|
popupData(clickState, features) {
|
|
60254
|
-
const featuresArray = features || clickState.viewport.
|
|
60151
|
+
const featuresArray = features || clickState.viewport.cachedFeatures;
|
|
60255
60152
|
|
|
60256
60153
|
if (featuresArray && featuresArray.length === this.tracks.length) {
|
|
60257
60154
|
// Array of feature arrays, 1 for each track
|
|
@@ -60268,40 +60165,24 @@
|
|
|
60268
60165
|
}
|
|
60269
60166
|
}
|
|
60270
60167
|
|
|
60271
|
-
supportsWholeGenome() {
|
|
60272
|
-
|
|
60273
|
-
return b;
|
|
60168
|
+
get supportsWholeGenome() {
|
|
60169
|
+
return this.tracks.every(track => track.supportsWholeGenome());
|
|
60274
60170
|
}
|
|
60275
60171
|
|
|
60276
60172
|
}
|
|
60277
60173
|
|
|
60278
60174
|
function autoscale(chr, featureArrays) {
|
|
60279
|
-
|
|
60280
|
-
|
|
60281
|
-
// if (chr === 'all') {
|
|
60282
|
-
// allValues = [];
|
|
60283
|
-
// featureArrays.forEach(function (features) {
|
|
60284
|
-
// features.forEach(function (f) {
|
|
60285
|
-
// if (!Number.isNaN(f.value)) {
|
|
60286
|
-
// allValues.push(f.value);
|
|
60287
|
-
// }
|
|
60288
|
-
// });
|
|
60289
|
-
// });
|
|
60290
|
-
//
|
|
60291
|
-
// min = Math.min(0, IGVMath.percentile(allValues, .1));
|
|
60292
|
-
// max = IGVMath.percentile(allValues, 99.9);
|
|
60293
|
-
//
|
|
60294
|
-
// }
|
|
60295
|
-
// else {
|
|
60175
|
+
let min = 0;
|
|
60176
|
+
let max = -Number.MAX_VALUE;
|
|
60296
60177
|
|
|
60297
|
-
|
|
60298
|
-
|
|
60178
|
+
for (let features of featureArrays) {
|
|
60179
|
+
for (let f of features) {
|
|
60299
60180
|
if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
|
|
60300
60181
|
min = Math.min(min, f.value);
|
|
60301
60182
|
max = Math.max(max, f.value);
|
|
60302
60183
|
}
|
|
60303
|
-
}
|
|
60304
|
-
}
|
|
60184
|
+
}
|
|
60185
|
+
}
|
|
60305
60186
|
|
|
60306
60187
|
return {
|
|
60307
60188
|
min: min,
|
|
@@ -60422,7 +60303,7 @@
|
|
|
60422
60303
|
return this;
|
|
60423
60304
|
}
|
|
60424
60305
|
|
|
60425
|
-
supportsWholeGenome() {
|
|
60306
|
+
get supportsWholeGenome() {
|
|
60426
60307
|
return true;
|
|
60427
60308
|
}
|
|
60428
60309
|
|
|
@@ -60843,7 +60724,7 @@
|
|
|
60843
60724
|
items = items.concat(MenuUtils.numericDataMenuItems(this.trackView));
|
|
60844
60725
|
}
|
|
60845
60726
|
|
|
60846
|
-
if (this.browser.circularView
|
|
60727
|
+
if (this.browser.circularView) {
|
|
60847
60728
|
items.push('<hr/>');
|
|
60848
60729
|
items.push({
|
|
60849
60730
|
label: 'Add interactions to circular view',
|
|
@@ -60860,7 +60741,7 @@
|
|
|
60860
60741
|
|
|
60861
60742
|
contextMenuItemList(clickState) {
|
|
60862
60743
|
// Experimental JBrowse feature
|
|
60863
|
-
if (this.browser.circularView
|
|
60744
|
+
if (this.browser.circularView) {
|
|
60864
60745
|
const viewport = clickState.viewport;
|
|
60865
60746
|
const list = [];
|
|
60866
60747
|
list.push({
|
|
@@ -60885,20 +60766,20 @@
|
|
|
60885
60766
|
const cachedFeatures = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end); // inView features are simply features that have been drawn, i.e. have a drawState
|
|
60886
60767
|
|
|
60887
60768
|
const inView = cachedFeatures.filter(f => f.drawState);
|
|
60888
|
-
if (inView.length === 0)
|
|
60889
|
-
|
|
60890
|
-
|
|
60891
|
-
|
|
60892
|
-
|
|
60893
|
-
const
|
|
60894
|
-
|
|
60895
|
-
|
|
60896
|
-
|
|
60897
|
-
this.
|
|
60898
|
-
|
|
60899
|
-
|
|
60900
|
-
|
|
60901
|
-
})
|
|
60769
|
+
if (inView.length === 0) return;
|
|
60770
|
+
const chords = makeBedPEChords(inView);
|
|
60771
|
+
sendChords(chords, this, refFrame, 0.5); //
|
|
60772
|
+
//
|
|
60773
|
+
// // for filtered set, distinguishing the chromosomes is more critical than tracks
|
|
60774
|
+
// const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.5)
|
|
60775
|
+
// const trackColor = IGVColor.addAlpha(this.color, 0.5)
|
|
60776
|
+
//
|
|
60777
|
+
// // name the chord set to include locus and filtering information
|
|
60778
|
+
// const encodedName = this.name.replaceAll(' ', '%20')
|
|
60779
|
+
// const chordSetName = "all" === refFrame.chr ?
|
|
60780
|
+
// encodedName :
|
|
60781
|
+
// `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end} ; range:${this.dataRange.min}-${this.dataRange.max})`
|
|
60782
|
+
// this.browser.circularView.addChords(chords, {track: chordSetName, color: chordSetColor, trackColor: trackColor})
|
|
60902
60783
|
}
|
|
60903
60784
|
|
|
60904
60785
|
doAutoscale(features) {
|
|
@@ -60985,7 +60866,7 @@
|
|
|
60985
60866
|
clickedFeatures(clickState, features) {
|
|
60986
60867
|
// We use the cached features rather than method to avoid async load. If the
|
|
60987
60868
|
// feature is not already loaded this won't work, but the user wouldn't be mousing over it either.
|
|
60988
|
-
const featureList = features || clickState.viewport.
|
|
60869
|
+
const featureList = features || clickState.viewport.cachedFeatures;
|
|
60989
60870
|
const candidates = [];
|
|
60990
60871
|
|
|
60991
60872
|
if (featureList) {
|
|
@@ -61356,7 +61237,7 @@
|
|
|
61356
61237
|
return this;
|
|
61357
61238
|
}
|
|
61358
61239
|
|
|
61359
|
-
supportsWholeGenome() {
|
|
61240
|
+
get supportsWholeGenome() {
|
|
61360
61241
|
return this.config.indexed === false || this.config.supportsWholeGenome === true;
|
|
61361
61242
|
}
|
|
61362
61243
|
|
|
@@ -61571,7 +61452,7 @@
|
|
|
61571
61452
|
variantColor = "gray";
|
|
61572
61453
|
}
|
|
61573
61454
|
} else if (this._color) {
|
|
61574
|
-
variantColor =
|
|
61455
|
+
variantColor = this.color;
|
|
61575
61456
|
} else if ("NONVARIANT" === v.type) {
|
|
61576
61457
|
variantColor = this.nonRefColor;
|
|
61577
61458
|
} else if ("MIXED" === v.type) {
|
|
@@ -61583,6 +61464,10 @@
|
|
|
61583
61464
|
return variantColor;
|
|
61584
61465
|
}
|
|
61585
61466
|
|
|
61467
|
+
get color() {
|
|
61468
|
+
return this._color ? typeof this._color === "function" ? this._color(v) : this._color : this.defaultColor;
|
|
61469
|
+
}
|
|
61470
|
+
|
|
61586
61471
|
clickedFeatures(clickState, features) {
|
|
61587
61472
|
let featureList = super.clickedFeatures(clickState, features);
|
|
61588
61473
|
const vGap = this.displayMode === 'EXPANDED' ? this.expandedVGap : this.squishedVGap;
|
|
@@ -61843,29 +61728,15 @@
|
|
|
61843
61728
|
} // Experimental JBrowse circular view integration
|
|
61844
61729
|
|
|
61845
61730
|
|
|
61846
|
-
if (this.browser.circularView
|
|
61731
|
+
if (this.browser.circularView) {
|
|
61847
61732
|
menuItems.push('<hr>');
|
|
61848
61733
|
menuItems.push({
|
|
61849
61734
|
label: 'Add SVs to circular view',
|
|
61850
61735
|
click: () => {
|
|
61851
|
-
const inView = [];
|
|
61852
61736
|
|
|
61853
61737
|
for (let viewport of this.trackView.viewports) {
|
|
61854
|
-
|
|
61855
|
-
|
|
61856
|
-
for (let f of viewport.getCachedFeatures()) {
|
|
61857
|
-
if (f.end >= refFrame.start && f.start <= refFrame.end) {
|
|
61858
|
-
inView.push(f);
|
|
61859
|
-
}
|
|
61860
|
-
}
|
|
61738
|
+
this.sendChordsForViewport(viewport);
|
|
61861
61739
|
}
|
|
61862
|
-
|
|
61863
|
-
const chords = makeVCFChords(inView);
|
|
61864
|
-
const color = IGVColor.addAlpha(this._color || this.defaultColor, 0.5);
|
|
61865
|
-
this.browser.circularView.addChords(chords, {
|
|
61866
|
-
track: this.name,
|
|
61867
|
-
color: color
|
|
61868
|
-
});
|
|
61869
61740
|
}
|
|
61870
61741
|
});
|
|
61871
61742
|
}
|
|
@@ -61875,26 +61746,26 @@
|
|
|
61875
61746
|
|
|
61876
61747
|
contextMenuItemList(clickState) {
|
|
61877
61748
|
// Experimental JBrowse circular view integration
|
|
61878
|
-
if (this.browser.circularView
|
|
61749
|
+
if (this.browser.circularView) {
|
|
61879
61750
|
const viewport = clickState.viewport;
|
|
61880
61751
|
const list = [];
|
|
61881
61752
|
list.push({
|
|
61882
61753
|
label: 'Add SVs to Circular View',
|
|
61883
61754
|
click: () => {
|
|
61884
|
-
|
|
61885
|
-
const inView = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
61886
|
-
const chords = makeVCFChords(inView);
|
|
61887
|
-
const color = IGVColor.addAlpha(this._color || this.defaultColor, 0.5);
|
|
61888
|
-
this.browser.circularView.addChords(chords, {
|
|
61889
|
-
track: this.name,
|
|
61890
|
-
color: color
|
|
61891
|
-
});
|
|
61755
|
+
this.sendChordsForViewport(viewport);
|
|
61892
61756
|
}
|
|
61893
61757
|
});
|
|
61894
61758
|
list.push('<hr/>');
|
|
61895
61759
|
return list;
|
|
61896
61760
|
}
|
|
61897
61761
|
}
|
|
61762
|
+
|
|
61763
|
+
sendChordsForViewport(viewport) {
|
|
61764
|
+
const refFrame = viewport.referenceFrame;
|
|
61765
|
+
const inView = "all" === refFrame.chr ? this.featureSource.getAllFeatures() : this.featureSource.featureCache.queryFeatures(refFrame.chr, refFrame.start, refFrame.end);
|
|
61766
|
+
const chords = makeVCFChords(inView);
|
|
61767
|
+
sendChords(chords, this, refFrame, 0.5);
|
|
61768
|
+
}
|
|
61898
61769
|
/**
|
|
61899
61770
|
* Create a "color by" checkbox menu item, optionally initially checked
|
|
61900
61771
|
* @param menuItem
|
|
@@ -62197,7 +62068,7 @@
|
|
|
62197
62068
|
|
|
62198
62069
|
|
|
62199
62070
|
popupData(clickState) {
|
|
62200
|
-
let features = clickState.viewport.
|
|
62071
|
+
let features = clickState.viewport.cachedFeatures;
|
|
62201
62072
|
if (!features || features.length === 0) return [];
|
|
62202
62073
|
const tolerance = 3;
|
|
62203
62074
|
const tissue = this.name;
|
|
@@ -62405,7 +62276,7 @@
|
|
|
62405
62276
|
return this;
|
|
62406
62277
|
}
|
|
62407
62278
|
|
|
62408
|
-
supportsWholeGenome() {
|
|
62279
|
+
get supportsWholeGenome() {
|
|
62409
62280
|
return true;
|
|
62410
62281
|
}
|
|
62411
62282
|
|
|
@@ -62543,7 +62414,7 @@
|
|
|
62543
62414
|
popupData(clickState) {
|
|
62544
62415
|
let data = [];
|
|
62545
62416
|
const track = clickState.viewport.trackView.track;
|
|
62546
|
-
const features = clickState.viewport.
|
|
62417
|
+
const features = clickState.viewport.cachedFeatures;
|
|
62547
62418
|
|
|
62548
62419
|
if (features) {
|
|
62549
62420
|
let count = 0;
|
|
@@ -62971,7 +62842,7 @@
|
|
|
62971
62842
|
return items;
|
|
62972
62843
|
}
|
|
62973
62844
|
|
|
62974
|
-
supportsWholeGenome() {
|
|
62845
|
+
get supportsWholeGenome() {
|
|
62975
62846
|
return false;
|
|
62976
62847
|
}
|
|
62977
62848
|
|
|
@@ -63232,7 +63103,7 @@
|
|
|
63232
63103
|
if (!this.featureCache) {
|
|
63233
63104
|
const options = buildOptions(this.config);
|
|
63234
63105
|
const data = await igvxhr.loadString(this.config.url, options);
|
|
63235
|
-
this.featureCache = new FeatureCache(parseBP(data), genome);
|
|
63106
|
+
this.featureCache = new FeatureCache$1(parseBP(data), genome);
|
|
63236
63107
|
return this.featureCache.queryFeatures(chr, start, end);
|
|
63237
63108
|
} else {
|
|
63238
63109
|
return this.featureCache.queryFeatures(chr, start, end);
|
|
@@ -63332,12 +63203,15 @@
|
|
|
63332
63203
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
63333
63204
|
* THE SOFTWARE.
|
|
63334
63205
|
*/
|
|
63206
|
+
/**
|
|
63207
|
+
* Class represents an ideogram of a chromsome cytobands. It is used for the header of a track panel.
|
|
63208
|
+
*
|
|
63209
|
+
*/
|
|
63335
63210
|
|
|
63336
63211
|
class IdeogramTrack {
|
|
63337
63212
|
constructor(browser) {
|
|
63338
63213
|
this.browser = browser;
|
|
63339
63214
|
this.type = 'ideogram';
|
|
63340
|
-
this.id = this.type;
|
|
63341
63215
|
this.height = 16;
|
|
63342
63216
|
this.order = Number.MIN_SAFE_INTEGER;
|
|
63343
63217
|
this.disableButtons = true;
|
|
@@ -63597,7 +63471,7 @@
|
|
|
63597
63471
|
return this;
|
|
63598
63472
|
}
|
|
63599
63473
|
|
|
63600
|
-
supportsWholeGenome() {
|
|
63474
|
+
get supportsWholeGenome() {
|
|
63601
63475
|
return false;
|
|
63602
63476
|
}
|
|
63603
63477
|
|
|
@@ -64475,6 +64349,15 @@
|
|
|
64475
64349
|
this.id = guid$2();
|
|
64476
64350
|
}
|
|
64477
64351
|
|
|
64352
|
+
extend(locus) {
|
|
64353
|
+
const newStart = Math.min(locus.start, this.start);
|
|
64354
|
+
const newEnd = Math.max(locus.end, this.end);
|
|
64355
|
+
const ratio = (newEnd - newStart) / (this.end - this.start);
|
|
64356
|
+
this.start = newStart;
|
|
64357
|
+
this.end = newEnd;
|
|
64358
|
+
this.bpPerPixel *= ratio;
|
|
64359
|
+
}
|
|
64360
|
+
|
|
64478
64361
|
calculateEnd(pixels) {
|
|
64479
64362
|
return this.start + this.bpPerPixel * pixels;
|
|
64480
64363
|
}
|
|
@@ -64559,7 +64442,7 @@
|
|
|
64559
64442
|
const viewChanged = start !== this.start || bpPerPixel !== this.bpPerPixel;
|
|
64560
64443
|
|
|
64561
64444
|
if (viewChanged) {
|
|
64562
|
-
await browser.updateViews(
|
|
64445
|
+
await browser.updateViews(true);
|
|
64563
64446
|
}
|
|
64564
64447
|
}
|
|
64565
64448
|
|
|
@@ -64629,23 +64512,6 @@
|
|
|
64629
64512
|
});
|
|
64630
64513
|
}
|
|
64631
64514
|
|
|
64632
|
-
function adjustReferenceFrame(scaleFactor, referenceFrame, viewportWidth, alignmentStart, alignmentLength) {
|
|
64633
|
-
referenceFrame.bpPerPixel *= scaleFactor;
|
|
64634
|
-
const alignmentEE = alignmentStart + alignmentLength;
|
|
64635
|
-
const alignmentCC = (alignmentStart + alignmentEE) / 2;
|
|
64636
|
-
referenceFrame.start = alignmentCC - referenceFrame.bpPerPixel * (viewportWidth / 2);
|
|
64637
|
-
referenceFrame.end = referenceFrame.start + referenceFrame.bpPerPixel * viewportWidth;
|
|
64638
|
-
referenceFrame.locusSearchString = referenceFrame.getLocusString();
|
|
64639
|
-
}
|
|
64640
|
-
|
|
64641
|
-
function createReferenceFrameWithAlignment(genome, chromosomeName, bpp, viewportWidth, alignmentStart, alignmentLength) {
|
|
64642
|
-
const alignmentEE = alignmentStart + alignmentLength;
|
|
64643
|
-
const alignmentCC = (alignmentStart + alignmentEE) / 2;
|
|
64644
|
-
const ss = alignmentCC - bpp * (viewportWidth / 2);
|
|
64645
|
-
const ee = ss + bpp * viewportWidth;
|
|
64646
|
-
return new ReferenceFrame(genome, chromosomeName, ss, ee, bpp);
|
|
64647
|
-
}
|
|
64648
|
-
|
|
64649
64515
|
const defaultNucleotideColors = {
|
|
64650
64516
|
"A": "rgb( 0, 200, 0)",
|
|
64651
64517
|
"C": "rgb( 0,0,200)",
|
|
@@ -65692,6 +65558,65 @@
|
|
|
65692
65558
|
button.addEventListener('click', () => browser.saveSVGtoFile({}));
|
|
65693
65559
|
};
|
|
65694
65560
|
|
|
65561
|
+
const viewportColumnManager = {
|
|
65562
|
+
createColumns: (columnContainer, count) => {
|
|
65563
|
+
for (let i = 0; i < count; i++) {
|
|
65564
|
+
if (0 === i) {
|
|
65565
|
+
createColumn(columnContainer, 'igv-column');
|
|
65566
|
+
} else {
|
|
65567
|
+
columnContainer.appendChild(div$1({
|
|
65568
|
+
class: 'igv-column-shim'
|
|
65569
|
+
}));
|
|
65570
|
+
createColumn(columnContainer, 'igv-column');
|
|
65571
|
+
}
|
|
65572
|
+
}
|
|
65573
|
+
},
|
|
65574
|
+
removeColumnAtIndex: (i, column) => {
|
|
65575
|
+
const shim = 0 === i ? column.nextElementSibling : column.previousElementSibling;
|
|
65576
|
+
column.remove();
|
|
65577
|
+
shim.remove();
|
|
65578
|
+
},
|
|
65579
|
+
insertAfter: referenceElement => {
|
|
65580
|
+
const shim = div$1({
|
|
65581
|
+
class: 'igv-column-shim'
|
|
65582
|
+
});
|
|
65583
|
+
insertElementAfter(shim, referenceElement);
|
|
65584
|
+
const column = div$1({
|
|
65585
|
+
class: 'igv-column'
|
|
65586
|
+
});
|
|
65587
|
+
insertElementAfter(column, shim);
|
|
65588
|
+
return column;
|
|
65589
|
+
},
|
|
65590
|
+
insertBefore: (referenceElement, count) => {
|
|
65591
|
+
for (let i = 0; i < count; i++) {
|
|
65592
|
+
const column = div$1({
|
|
65593
|
+
class: 'igv-column'
|
|
65594
|
+
});
|
|
65595
|
+
insertElementBefore(column, referenceElement);
|
|
65596
|
+
|
|
65597
|
+
if (count > 1 && i > 0) {
|
|
65598
|
+
const columnShim = div$1({
|
|
65599
|
+
class: 'igv-column-shim'
|
|
65600
|
+
});
|
|
65601
|
+
insertElementBefore(columnShim, column);
|
|
65602
|
+
}
|
|
65603
|
+
}
|
|
65604
|
+
},
|
|
65605
|
+
indexOfColumn: (columnContainer, column) => {
|
|
65606
|
+
const allColumns = columnContainer.querySelectorAll('.igv-column');
|
|
65607
|
+
|
|
65608
|
+
for (let i = 0; i < allColumns.length; i++) {
|
|
65609
|
+
const c = allColumns[i];
|
|
65610
|
+
|
|
65611
|
+
if (c === column) {
|
|
65612
|
+
return i;
|
|
65613
|
+
}
|
|
65614
|
+
}
|
|
65615
|
+
|
|
65616
|
+
return undefined;
|
|
65617
|
+
}
|
|
65618
|
+
};
|
|
65619
|
+
|
|
65695
65620
|
/*
|
|
65696
65621
|
* The MIT License (MIT)
|
|
65697
65622
|
*
|
|
@@ -65942,7 +65867,7 @@
|
|
|
65942
65867
|
}
|
|
65943
65868
|
}
|
|
65944
65869
|
|
|
65945
|
-
supportsWholeGenome() {
|
|
65870
|
+
get supportsWholeGenome() {
|
|
65946
65871
|
return true;
|
|
65947
65872
|
}
|
|
65948
65873
|
|
|
@@ -66474,7 +66399,9 @@
|
|
|
66474
66399
|
// deferred because ideogram and ruler are treated as "tracks", and tracks require a reference frame
|
|
66475
66400
|
|
|
66476
66401
|
if (false !== session.showIdeogram) {
|
|
66477
|
-
|
|
66402
|
+
const ideogramTrack = new IdeogramTrack(this);
|
|
66403
|
+
ideogramTrack.id = 'ideogram';
|
|
66404
|
+
this.trackViews.push(new TrackView(this, this.columnContainer, ideogramTrack));
|
|
66478
66405
|
}
|
|
66479
66406
|
|
|
66480
66407
|
if (false !== session.showRuler) {
|
|
@@ -66524,7 +66451,12 @@
|
|
|
66524
66451
|
}
|
|
66525
66452
|
}
|
|
66526
66453
|
|
|
66527
|
-
await this.loadTrackList(trackConfigurations);
|
|
66454
|
+
await this.loadTrackList(trackConfigurations); // The ruler and ideogram tracks are not explicitly loaded, but needs updated nonetheless.
|
|
66455
|
+
|
|
66456
|
+
for (let rtv of this.trackViews.filter(tv => tv.track.type === 'ruler' || tv.track.type === 'ideogram')) {
|
|
66457
|
+
rtv.updateViews();
|
|
66458
|
+
}
|
|
66459
|
+
|
|
66528
66460
|
this.updateUIWithReferenceFrameList();
|
|
66529
66461
|
}
|
|
66530
66462
|
|
|
@@ -66689,26 +66621,22 @@
|
|
|
66689
66621
|
}
|
|
66690
66622
|
|
|
66691
66623
|
async loadTrackList(configList) {
|
|
66692
|
-
|
|
66693
|
-
const promises = [];
|
|
66694
|
-
|
|
66695
|
-
for (let config of configList) {
|
|
66696
|
-
promises.push(this.loadTrack(config, false));
|
|
66697
|
-
}
|
|
66624
|
+
const promises = [];
|
|
66698
66625
|
|
|
66699
|
-
|
|
66700
|
-
|
|
66701
|
-
|
|
66702
|
-
});
|
|
66626
|
+
for (let config of configList) {
|
|
66627
|
+
promises.push(this.loadTrack(config));
|
|
66628
|
+
}
|
|
66703
66629
|
|
|
66704
|
-
|
|
66705
|
-
|
|
66706
|
-
|
|
66630
|
+
const loadedTracks = await Promise.all(promises);
|
|
66631
|
+
const groupAutoscaleViews = this.trackViews.filter(function (trackView) {
|
|
66632
|
+
return trackView.track.autoscaleGroup;
|
|
66633
|
+
});
|
|
66707
66634
|
|
|
66708
|
-
|
|
66709
|
-
|
|
66710
|
-
await this.resize();
|
|
66635
|
+
if (groupAutoscaleViews.length > 0) {
|
|
66636
|
+
this.updateViews();
|
|
66711
66637
|
}
|
|
66638
|
+
|
|
66639
|
+
return loadedTracks;
|
|
66712
66640
|
}
|
|
66713
66641
|
|
|
66714
66642
|
async loadROI(config) {
|
|
@@ -66722,7 +66650,9 @@
|
|
|
66722
66650
|
}
|
|
66723
66651
|
} else {
|
|
66724
66652
|
this.roi.push(new ROI(config, this.genome));
|
|
66725
|
-
}
|
|
66653
|
+
} // Force reload all views (force = true) to insure ROI features are loaded. Wasteful but this function is
|
|
66654
|
+
// rarely called.
|
|
66655
|
+
|
|
66726
66656
|
|
|
66727
66657
|
await this.updateViews(true);
|
|
66728
66658
|
}
|
|
@@ -66736,7 +66666,7 @@
|
|
|
66736
66666
|
}
|
|
66737
66667
|
|
|
66738
66668
|
for (let tv of this.trackViews) {
|
|
66739
|
-
tv.
|
|
66669
|
+
tv.repaintViews();
|
|
66740
66670
|
}
|
|
66741
66671
|
}
|
|
66742
66672
|
|
|
@@ -66744,7 +66674,7 @@
|
|
|
66744
66674
|
this.roi = [];
|
|
66745
66675
|
|
|
66746
66676
|
for (let tv of this.trackViews) {
|
|
66747
|
-
tv.
|
|
66677
|
+
tv.repaintViews();
|
|
66748
66678
|
}
|
|
66749
66679
|
}
|
|
66750
66680
|
|
|
@@ -66760,25 +66690,13 @@
|
|
|
66760
66690
|
/**
|
|
66761
66691
|
* Return a promise to load a track.
|
|
66762
66692
|
*
|
|
66763
|
-
* Each track is associated with the following DOM elements
|
|
66764
|
-
*
|
|
66765
|
-
* leftHandGutter - div on the left for track controls and legend
|
|
66766
|
-
* contentDiv - a div element wrapping all the track content. Height can be > viewportDiv height
|
|
66767
|
-
* viewportDiv - a div element through which the track is viewed. This might have a vertical scrollbar
|
|
66768
|
-
* canvas - canvas element upon which the track is drawn. Child of contentDiv
|
|
66769
|
-
*
|
|
66770
|
-
* The width of all elements should be equal. Height of the viewportDiv is controlled by the user, but never
|
|
66771
|
-
* greater than the contentDiv height. Height of contentDiv and canvas are equal, and governed by the data
|
|
66772
|
-
* loaded.
|
|
66773
|
-
*
|
|
66774
|
-
*
|
|
66775
66693
|
* @param config
|
|
66776
66694
|
* @param doResize - undefined by default
|
|
66777
66695
|
* @returns {*}
|
|
66778
66696
|
*/
|
|
66779
66697
|
|
|
66780
66698
|
|
|
66781
|
-
async loadTrack(config
|
|
66699
|
+
async loadTrack(config) {
|
|
66782
66700
|
// config might be json
|
|
66783
66701
|
if (isString$3(config)) {
|
|
66784
66702
|
config = JSON.parse(config);
|
|
@@ -66843,11 +66761,6 @@
|
|
|
66843
66761
|
|
|
66844
66762
|
msg += ": " + config.url;
|
|
66845
66763
|
Alert.presentAlert(new Error(msg), undefined);
|
|
66846
|
-
} finally {
|
|
66847
|
-
// TODO: If loadTrack() is called individually - not via loadTrackList() - call this.resize()
|
|
66848
|
-
if (false === doResize) ; else {
|
|
66849
|
-
await this.resize();
|
|
66850
|
-
}
|
|
66851
66764
|
}
|
|
66852
66765
|
}
|
|
66853
66766
|
/**
|
|
@@ -67080,43 +66993,11 @@
|
|
|
67080
66993
|
this.navbarManager.navbarDidResize(this.$navigation.width(), isWGV);
|
|
67081
66994
|
}
|
|
67082
66995
|
|
|
67083
|
-
|
|
67084
|
-
|
|
67085
|
-
|
|
67086
|
-
async resize() {
|
|
67087
|
-
const viewportWidth = this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67088
|
-
|
|
67089
|
-
for (let referenceFrame of this.referenceFrameList) {
|
|
67090
|
-
const index = this.referenceFrameList.indexOf(referenceFrame);
|
|
67091
|
-
const {
|
|
67092
|
-
chr,
|
|
67093
|
-
genome
|
|
67094
|
-
} = referenceFrame;
|
|
67095
|
-
const {
|
|
67096
|
-
bpLength
|
|
67097
|
-
} = genome.getChromosome(referenceFrame.chr);
|
|
67098
|
-
const viewportWidthBP = referenceFrame.toBP(viewportWidth); // viewportWidthBP > bpLength occurs when locus is full chromosome and user widens browser
|
|
67099
|
-
|
|
67100
|
-
if (GenomeUtils.isWholeGenomeView(chr) || viewportWidthBP > bpLength) {
|
|
67101
|
-
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) bpp. viewport ${ StringUtils.numberFormatter(viewportWidthBP) } > ${ StringUtils.numberFormatter(bpLength) }.`)
|
|
67102
|
-
referenceFrame.bpPerPixel = bpLength / viewportWidth;
|
|
67103
|
-
} else {
|
|
67104
|
-
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) end.`)
|
|
67105
|
-
referenceFrame.end = referenceFrame.start + referenceFrame.toBP(viewportWidth);
|
|
67106
|
-
}
|
|
67107
|
-
|
|
67108
|
-
for (let {
|
|
67109
|
-
viewports
|
|
67110
|
-
} of this.trackViews) {
|
|
67111
|
-
viewports[index].setWidth(viewportWidth);
|
|
67112
|
-
}
|
|
67113
|
-
}
|
|
67114
|
-
|
|
67115
|
-
await this.updateViews(true);
|
|
67116
|
-
this.updateUIWithReferenceFrameList();
|
|
66996
|
+
resize.call(this);
|
|
66997
|
+
await this.updateViews();
|
|
67117
66998
|
}
|
|
67118
66999
|
|
|
67119
|
-
async updateViews(
|
|
67000
|
+
async updateViews() {
|
|
67120
67001
|
const trackViews = this.trackViews;
|
|
67121
67002
|
this.updateLocusSearchWidget();
|
|
67122
67003
|
|
|
@@ -67127,7 +67008,7 @@
|
|
|
67127
67008
|
|
|
67128
67009
|
if (this.dragObject) {
|
|
67129
67010
|
for (let trackView of trackViews) {
|
|
67130
|
-
await trackView.updateViews(
|
|
67011
|
+
await trackView.updateViews();
|
|
67131
67012
|
}
|
|
67132
67013
|
} else {
|
|
67133
67014
|
// Group autoscale
|
|
@@ -67176,19 +67057,25 @@
|
|
|
67176
67057
|
for (let trackView of groupTrackViews) {
|
|
67177
67058
|
trackView.track.dataRange = dataRange;
|
|
67178
67059
|
trackView.track.autoscale = false;
|
|
67179
|
-
p.push(trackView.updateViews(
|
|
67060
|
+
p.push(trackView.updateViews());
|
|
67180
67061
|
}
|
|
67181
67062
|
|
|
67182
67063
|
await Promise.all(p);
|
|
67183
67064
|
}
|
|
67184
67065
|
}
|
|
67185
67066
|
|
|
67186
|
-
await Promise.all(otherTracks.map(tv => tv.updateViews(
|
|
67067
|
+
await Promise.all(otherTracks.map(tv => tv.updateViews())); // for (let trackView of otherTracks) {
|
|
67187
67068
|
// await trackView.updateViews(force);
|
|
67188
67069
|
// }
|
|
67189
67070
|
}
|
|
67190
67071
|
}
|
|
67191
67072
|
|
|
67073
|
+
repaintViews() {
|
|
67074
|
+
for (let trackView of this.trackViews) {
|
|
67075
|
+
trackView.repaintViews();
|
|
67076
|
+
}
|
|
67077
|
+
}
|
|
67078
|
+
|
|
67192
67079
|
updateLocusSearchWidget() {
|
|
67193
67080
|
const referenceFrameList = this.referenceFrameList; // Update end position of reference frames based on pixel widths. This is hacky, but its been done here
|
|
67194
67081
|
// for a long time, although indirectly.
|
|
@@ -67246,41 +67133,53 @@
|
|
|
67246
67133
|
referenceFrame.zoomWithScaleFactor(this, scaleFactor, viewportWidth, centerBPOrUndefined);
|
|
67247
67134
|
}
|
|
67248
67135
|
}
|
|
67136
|
+
/**
|
|
67137
|
+
* Add a new multi-locus panel for the specified region
|
|
67138
|
+
* @param chr
|
|
67139
|
+
* @param start
|
|
67140
|
+
* @param end
|
|
67141
|
+
* @param referenceFrameLeft - optional, if supplied new panel should be placed to the immediate right
|
|
67142
|
+
*/
|
|
67143
|
+
|
|
67249
67144
|
|
|
67250
|
-
async
|
|
67145
|
+
async addMultiLocusPanel(chr, start, end, referenceFrameLeft) {
|
|
67251
67146
|
// account for reduced viewport width as a result of adding right mate pair panel
|
|
67252
67147
|
const viewportWidth = this.calculateViewportWidth(1 + this.referenceFrameList.length);
|
|
67253
67148
|
const scaleFactor = this.calculateViewportWidth(this.referenceFrameList.length) / this.calculateViewportWidth(1 + this.referenceFrameList.length);
|
|
67254
|
-
adjustReferenceFrame(scaleFactor, referenceFrameLeft, viewportWidth, alignment.start, alignment.lengthOnRef); // create right mate pair reference frame
|
|
67255
67149
|
|
|
67256
|
-
|
|
67257
|
-
|
|
67150
|
+
for (let refFrame of this.referenceFrameList) {
|
|
67151
|
+
refFrame.bpPerPixel *= scaleFactor;
|
|
67152
|
+
}
|
|
67153
|
+
|
|
67154
|
+
const bpp = (end - start) / viewportWidth;
|
|
67155
|
+
const newReferenceFrame = new ReferenceFrame(this.genome, chr, start, end, bpp);
|
|
67156
|
+
const indexLeft = referenceFrameLeft ? this.referenceFrameList.indexOf(referenceFrameLeft) : this.referenceFrameList.length - 1;
|
|
67157
|
+
const indexRight = 1 + indexLeft; // TODO -- this is really ugly
|
|
67258
67158
|
|
|
67259
|
-
const indexLeft = this.referenceFrameList.indexOf(referenceFrameLeft);
|
|
67260
|
-
const indexRight = 1 + this.referenceFrameList.indexOf(referenceFrameLeft);
|
|
67261
67159
|
const {
|
|
67262
67160
|
$viewport
|
|
67263
67161
|
} = this.trackViews[0].viewports[indexLeft];
|
|
67264
67162
|
const viewportColumn = viewportColumnManager.insertAfter($viewport.get(0).parentElement);
|
|
67265
67163
|
|
|
67266
67164
|
if (indexRight === this.referenceFrameList.length) {
|
|
67267
|
-
this.referenceFrameList.push(
|
|
67165
|
+
this.referenceFrameList.push(newReferenceFrame);
|
|
67268
67166
|
|
|
67269
67167
|
for (let trackView of this.trackViews) {
|
|
67270
|
-
const viewport = createViewport(trackView, viewportColumn,
|
|
67168
|
+
const viewport = createViewport(trackView, viewportColumn, newReferenceFrame);
|
|
67271
67169
|
trackView.viewports.push(viewport);
|
|
67272
67170
|
}
|
|
67273
67171
|
} else {
|
|
67274
|
-
this.referenceFrameList.splice(indexRight, 0,
|
|
67172
|
+
this.referenceFrameList.splice(indexRight, 0, newReferenceFrame);
|
|
67275
67173
|
|
|
67276
67174
|
for (let trackView of this.trackViews) {
|
|
67277
|
-
const viewport = createViewport(trackView, viewportColumn,
|
|
67175
|
+
const viewport = createViewport(trackView, viewportColumn, newReferenceFrame);
|
|
67278
67176
|
trackView.viewports.splice(indexRight, 0, viewport);
|
|
67279
67177
|
}
|
|
67280
67178
|
}
|
|
67281
67179
|
|
|
67282
67180
|
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
67283
|
-
|
|
67181
|
+
resize.call(this);
|
|
67182
|
+
await this.updateViews(true);
|
|
67284
67183
|
}
|
|
67285
67184
|
|
|
67286
67185
|
async removeMultiLocusPanel(referenceFrame) {
|
|
@@ -67309,8 +67208,15 @@
|
|
|
67309
67208
|
const scaleFactor = this.calculateViewportWidth(1 + this.referenceFrameList.length) / this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67310
67209
|
await this.rescaleForMultiLocus(scaleFactor);
|
|
67311
67210
|
}
|
|
67211
|
+
/**
|
|
67212
|
+
* Goto the locus represented by the selected referenceFrame, discarding all other panels
|
|
67213
|
+
*
|
|
67214
|
+
* @param referenceFrame
|
|
67215
|
+
* @returns {Promise<void>}
|
|
67216
|
+
*/
|
|
67217
|
+
|
|
67312
67218
|
|
|
67313
|
-
async
|
|
67219
|
+
async gotoMultilocusPanel(referenceFrame) {
|
|
67314
67220
|
const referenceFrameIndex = this.referenceFrameList.indexOf(referenceFrame); // Remove columns for unselected panels
|
|
67315
67221
|
|
|
67316
67222
|
this.columnContainer.querySelectorAll('.igv-column').forEach((column, c) => {
|
|
@@ -67358,7 +67264,7 @@
|
|
|
67358
67264
|
|
|
67359
67265
|
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
67360
67266
|
this.updateUIWithReferenceFrameList();
|
|
67361
|
-
await this.updateViews(
|
|
67267
|
+
await this.updateViews();
|
|
67362
67268
|
}
|
|
67363
67269
|
/**
|
|
67364
67270
|
* @deprecated This is a deprecated method with no known usages. To be removed in a future release.
|
|
@@ -67611,20 +67517,6 @@
|
|
|
67611
67517
|
const surl = (idx > 0 ? path.substring(0, idx) : path) + "?sessionURL=blob:" + this.compressedSession();
|
|
67612
67518
|
return surl;
|
|
67613
67519
|
}
|
|
67614
|
-
|
|
67615
|
-
currentLoci() {
|
|
67616
|
-
const loci = [];
|
|
67617
|
-
const anyTrackView = this.trackViews[0];
|
|
67618
|
-
|
|
67619
|
-
for (let {
|
|
67620
|
-
referenceFrame
|
|
67621
|
-
} of anyTrackView.viewports) {
|
|
67622
|
-
const locusString = referenceFrame.getLocusString();
|
|
67623
|
-
loci.push(locusString);
|
|
67624
|
-
}
|
|
67625
|
-
|
|
67626
|
-
return loci;
|
|
67627
|
-
}
|
|
67628
67520
|
/**
|
|
67629
67521
|
* Record a mouse click on a specific viewport. This might be the start of a drag operation. Dragging
|
|
67630
67522
|
* (panning) is handled here so that the mouse can move out of a specific viewport (e.g. stray into another
|
|
@@ -67659,10 +67551,22 @@
|
|
|
67659
67551
|
this.fireEvent('trackdragend');
|
|
67660
67552
|
}
|
|
67661
67553
|
}
|
|
67554
|
+
/**
|
|
67555
|
+
* Track drag here refers to vertical dragging to reorder tracks, not horizontal panning.
|
|
67556
|
+
*
|
|
67557
|
+
* @param trackView
|
|
67558
|
+
*/
|
|
67559
|
+
|
|
67662
67560
|
|
|
67663
67561
|
startTrackDrag(trackView) {
|
|
67664
67562
|
this.dragTrack = trackView;
|
|
67665
67563
|
}
|
|
67564
|
+
/**
|
|
67565
|
+
* Track drag here refers to vertical dragging to reorder tracks, not horizontal panning.
|
|
67566
|
+
*
|
|
67567
|
+
* @param dragDestination
|
|
67568
|
+
*/
|
|
67569
|
+
|
|
67666
67570
|
|
|
67667
67571
|
updateTrackDrag(dragDestination) {
|
|
67668
67572
|
if (dragDestination && this.dragTrack) {
|
|
@@ -67736,12 +67640,9 @@
|
|
|
67736
67640
|
}
|
|
67737
67641
|
|
|
67738
67642
|
addWindowResizeHandler() {
|
|
67739
|
-
this.
|
|
67643
|
+
// Create a copy of the prototype "resize" function bound to this instance. Neccessary to support removing.
|
|
67644
|
+
this.boundWindowResizeHandler = resize.bind(this);
|
|
67740
67645
|
window.addEventListener('resize', this.boundWindowResizeHandler);
|
|
67741
|
-
|
|
67742
|
-
function windowResizeHandler() {
|
|
67743
|
-
this.resize();
|
|
67744
|
-
}
|
|
67745
67646
|
}
|
|
67746
67647
|
|
|
67747
67648
|
removeWindowResizeHandler() {
|
|
@@ -67820,7 +67721,7 @@
|
|
|
67820
67721
|
id: this.genome.id,
|
|
67821
67722
|
chromosomes: makeCircViewChromosomes(this.genome)
|
|
67822
67723
|
});
|
|
67823
|
-
this.circularViewVisible = show
|
|
67724
|
+
this.circularViewVisible = show;
|
|
67824
67725
|
}
|
|
67825
67726
|
|
|
67826
67727
|
get circularViewVisible() {
|
|
@@ -67835,6 +67736,48 @@
|
|
|
67835
67736
|
}
|
|
67836
67737
|
|
|
67837
67738
|
}
|
|
67739
|
+
/**
|
|
67740
|
+
* Function called win window is resized, or visibility changed (e.g. "show" from a tab). This is a function rather
|
|
67741
|
+
* than class method because it needs to be copied and bound to specific instances of browser to support listener
|
|
67742
|
+
* removal
|
|
67743
|
+
*
|
|
67744
|
+
* @returns {Promise<void>}
|
|
67745
|
+
*/
|
|
67746
|
+
|
|
67747
|
+
|
|
67748
|
+
async function resize() {
|
|
67749
|
+
const viewportWidth = this.calculateViewportWidth(this.referenceFrameList.length);
|
|
67750
|
+
|
|
67751
|
+
for (let referenceFrame of this.referenceFrameList) {
|
|
67752
|
+
const index = this.referenceFrameList.indexOf(referenceFrame);
|
|
67753
|
+
const {
|
|
67754
|
+
chr,
|
|
67755
|
+
genome
|
|
67756
|
+
} = referenceFrame;
|
|
67757
|
+
const {
|
|
67758
|
+
bpLength
|
|
67759
|
+
} = genome.getChromosome(referenceFrame.chr);
|
|
67760
|
+
const viewportWidthBP = referenceFrame.toBP(viewportWidth); // viewportWidthBP > bpLength occurs when locus is full chromosome and user widens browser
|
|
67761
|
+
|
|
67762
|
+
if (GenomeUtils.isWholeGenomeView(chr) || viewportWidthBP > bpLength) {
|
|
67763
|
+
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) bpp. viewport ${ StringUtils.numberFormatter(viewportWidthBP) } > ${ StringUtils.numberFormatter(bpLength) }.`)
|
|
67764
|
+
referenceFrame.bpPerPixel = bpLength / viewportWidth;
|
|
67765
|
+
} else {
|
|
67766
|
+
// console.log(`${ Date.now() } Recalc referenceFrame(${ index }) end.`)
|
|
67767
|
+
referenceFrame.end = referenceFrame.start + referenceFrame.toBP(viewportWidth);
|
|
67768
|
+
}
|
|
67769
|
+
|
|
67770
|
+
for (let {
|
|
67771
|
+
viewports
|
|
67772
|
+
} of this.trackViews) {
|
|
67773
|
+
viewports[index].setWidth(viewportWidth);
|
|
67774
|
+
}
|
|
67775
|
+
}
|
|
67776
|
+
|
|
67777
|
+
this.updateUIWithReferenceFrameList(); //TODO -- update view only if needed. Reducing size never needed. Increasing size maybe
|
|
67778
|
+
|
|
67779
|
+
await this.updateViews(true);
|
|
67780
|
+
}
|
|
67838
67781
|
|
|
67839
67782
|
function handleMouseMove(e) {
|
|
67840
67783
|
e.preventDefault();
|