igv 3.0.8 → 3.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/igv.esm.js +1303 -777
- package/dist/igv.esm.min.js +10 -10
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +1303 -777
- package/dist/igv.min.js +10 -10
- package/dist/igv.min.js.map +1 -1
- package/package.json +1 -1
package/dist/igv.esm.js
CHANGED
|
@@ -18593,7 +18593,7 @@ function rgbStringHeatMapLerp(_a, _b, interpolant) {
|
|
|
18593
18593
|
|
|
18594
18594
|
}
|
|
18595
18595
|
|
|
18596
|
-
const colorPickerTrackTypeSet = new Set(['bedtype', 'alignment', 'annotation', 'variant', 'wig', 'interact']);
|
|
18596
|
+
const colorPickerTrackTypeSet = new Set(['bedtype', 'alignment', 'annotation', 'variant', 'wig', 'interact', 'shoebox']);
|
|
18597
18597
|
|
|
18598
18598
|
const vizWindowTypes = new Set(['alignment', 'annotation', 'variant', 'eqtl', 'qtl', 'snp', 'shoebox', 'wig']);
|
|
18599
18599
|
|
|
@@ -20936,125 +20936,6 @@ function createDOMPurify() {
|
|
|
20936
20936
|
}
|
|
20937
20937
|
var purify = createDOMPurify();
|
|
20938
20938
|
|
|
20939
|
-
class SliderDialog {
|
|
20940
|
-
|
|
20941
|
-
constructor(parent) {
|
|
20942
|
-
|
|
20943
|
-
this.parent = parent;
|
|
20944
|
-
|
|
20945
|
-
// dialog container
|
|
20946
|
-
this.container = div({class: 'igv-ui-generic-dialog-container'});
|
|
20947
|
-
parent.appendChild(this.container);
|
|
20948
|
-
|
|
20949
|
-
// dialog header
|
|
20950
|
-
const header = div({class: 'igv-ui-generic-dialog-header'});
|
|
20951
|
-
this.container.appendChild(header);
|
|
20952
|
-
|
|
20953
|
-
// dialog label
|
|
20954
|
-
this.label = div({class: 'igv-ui-generic-dialog-one-liner'});
|
|
20955
|
-
this.container.appendChild(this.label);
|
|
20956
|
-
this.label.text = 'Unlabeled';
|
|
20957
|
-
|
|
20958
|
-
// input container
|
|
20959
|
-
this.input_container = div({class: 'igv-ui-generic-dialog-input'});
|
|
20960
|
-
this.container.appendChild(this.input_container);
|
|
20961
|
-
|
|
20962
|
-
// input element
|
|
20963
|
-
let html = `<input type="range" id="igv-slider-dialog-input" name="igv-slider-dialog-input" />`;
|
|
20964
|
-
this._input = document.createRange().createContextualFragment(html).firstChild;
|
|
20965
|
-
this.input_container.appendChild(this._input);
|
|
20966
|
-
|
|
20967
|
-
// output element
|
|
20968
|
-
html = `<output id="igv-slider-dialog-output" name="igv-slider-dialog-output" for="igv-slider-dialog-input"></output>`;
|
|
20969
|
-
this._output = document.createRange().createContextualFragment(html).firstChild;
|
|
20970
|
-
this.input_container.appendChild(this._output);
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
// ok | cancel
|
|
20974
|
-
const buttons = div({class: 'igv-ui-generic-dialog-ok-cancel'});
|
|
20975
|
-
this.container.appendChild(buttons);
|
|
20976
|
-
|
|
20977
|
-
// ok
|
|
20978
|
-
this.ok = div();
|
|
20979
|
-
buttons.appendChild(this.ok);
|
|
20980
|
-
this.ok.textContent = 'OK';
|
|
20981
|
-
|
|
20982
|
-
// cancel
|
|
20983
|
-
this.cancel = div();
|
|
20984
|
-
buttons.appendChild(this.cancel);
|
|
20985
|
-
this.cancel.textContent = 'Cancel';
|
|
20986
|
-
|
|
20987
|
-
hide(this.container);
|
|
20988
|
-
|
|
20989
|
-
this._input.addEventListener('input', () => {
|
|
20990
|
-
const number = parseFloat(this._input.value)/this._scaleFactor;
|
|
20991
|
-
this.callback(number);
|
|
20992
|
-
this._output.value = `${number.toFixed(2)}`;
|
|
20993
|
-
}, false);
|
|
20994
|
-
|
|
20995
|
-
this.ok.addEventListener('click', () => {
|
|
20996
|
-
if (typeof this.callback === 'function') {
|
|
20997
|
-
const number = parseFloat(this._input.value)/this._scaleFactor;
|
|
20998
|
-
this.callback(number);
|
|
20999
|
-
this.callback = undefined;
|
|
21000
|
-
}
|
|
21001
|
-
this._input.value = undefined;
|
|
21002
|
-
hide(this.container);
|
|
21003
|
-
});
|
|
21004
|
-
|
|
21005
|
-
const cancel = () => {
|
|
21006
|
-
this._input.value = undefined;
|
|
21007
|
-
hide(this.container);
|
|
21008
|
-
};
|
|
21009
|
-
|
|
21010
|
-
this.cancel.addEventListener('click', cancel);
|
|
21011
|
-
|
|
21012
|
-
attachDialogCloseHandlerWithParent(header, cancel);
|
|
21013
|
-
makeDraggable(this.container, header);
|
|
21014
|
-
|
|
21015
|
-
}
|
|
21016
|
-
|
|
21017
|
-
get value() {
|
|
21018
|
-
return purify.sanitize(this._input.value)
|
|
21019
|
-
}
|
|
21020
|
-
|
|
21021
|
-
present(options, e) {
|
|
21022
|
-
|
|
21023
|
-
this.label.textContent = options.label;
|
|
21024
|
-
|
|
21025
|
-
this._scaleFactor = options.scaleFactor;
|
|
21026
|
-
const [ minS, maxS, valueS ] = [ options.min, options.max, options.value ].map(number => (Math.floor(this._scaleFactor * number)).toString());
|
|
21027
|
-
|
|
21028
|
-
this._input.min = minS;
|
|
21029
|
-
this._input.max = maxS;
|
|
21030
|
-
this._input.value = valueS;
|
|
21031
|
-
|
|
21032
|
-
const numer = parseFloat(valueS);
|
|
21033
|
-
const denom = this._scaleFactor;
|
|
21034
|
-
const number = numer/denom;
|
|
21035
|
-
this._output.value = `${number.toFixed(2)}`;
|
|
21036
|
-
|
|
21037
|
-
this.callback = options.callback || options.click;
|
|
21038
|
-
|
|
21039
|
-
show(this.container);
|
|
21040
|
-
this.clampLocation(e.clientX, e.clientY);
|
|
21041
|
-
|
|
21042
|
-
}
|
|
21043
|
-
|
|
21044
|
-
clampLocation(clientX, clientY) {
|
|
21045
|
-
|
|
21046
|
-
const {width: w, height: h} = this.container.getBoundingClientRect();
|
|
21047
|
-
const wh = window.innerHeight;
|
|
21048
|
-
const ww = window.innerWidth;
|
|
21049
|
-
|
|
21050
|
-
const y = Math.min(wh - h, clientY);
|
|
21051
|
-
const x = Math.min(ww - w, clientX);
|
|
21052
|
-
this.container.style.left = `${x}px`;
|
|
21053
|
-
this.container.style.top = `${y}px`;
|
|
21054
|
-
|
|
21055
|
-
}
|
|
21056
|
-
}
|
|
21057
|
-
|
|
21058
20939
|
class InputDialog {
|
|
21059
20940
|
|
|
21060
20941
|
constructor(parent) {
|
|
@@ -24508,6 +24389,29 @@ function decodeSNP(tokens, header) {
|
|
|
24508
24389
|
|
|
24509
24390
|
}
|
|
24510
24391
|
|
|
24392
|
+
function decodeShoebox(tokens, header, maxColumnCount = Number.MAX_SAFE_INTEGER) {
|
|
24393
|
+
|
|
24394
|
+
if (tokens.length < 4) return undefined
|
|
24395
|
+
|
|
24396
|
+
const chr = tokens[0];
|
|
24397
|
+
const start = parseInt(tokens[1]);
|
|
24398
|
+
const end = tokens.length > 2 ? parseInt(tokens[2]) : start + 1;
|
|
24399
|
+
if (isNaN(start) || isNaN(end)) {
|
|
24400
|
+
return new DecodeError(`Unparsable bed record.`)
|
|
24401
|
+
}
|
|
24402
|
+
const feature = new UCSCBedFeature({chr: chr, start: start, end: end, score: 1000});
|
|
24403
|
+
|
|
24404
|
+
const values = [];
|
|
24405
|
+
for(let i = 3; i< tokens.length; i++) {
|
|
24406
|
+
values.push(Number.parseInt(tokens[i]));
|
|
24407
|
+
}
|
|
24408
|
+
feature.values = values;
|
|
24409
|
+
|
|
24410
|
+
|
|
24411
|
+
return feature
|
|
24412
|
+
}
|
|
24413
|
+
|
|
24414
|
+
|
|
24511
24415
|
class UCSCBedFeature {
|
|
24512
24416
|
|
|
24513
24417
|
constructor(properties) {
|
|
@@ -25872,6 +25776,10 @@ class FeatureParser {
|
|
|
25872
25776
|
this.decode = decodeGcnv;
|
|
25873
25777
|
this.delimiter = "\t";
|
|
25874
25778
|
break
|
|
25779
|
+
case "shoebox":
|
|
25780
|
+
this.decode = decodeShoebox;
|
|
25781
|
+
this.delimiter = "\t";
|
|
25782
|
+
break
|
|
25875
25783
|
default:
|
|
25876
25784
|
const customFormat = getFormat(format);
|
|
25877
25785
|
if (customFormat !== undefined) {
|
|
@@ -31958,14 +31866,25 @@ class BWReader {
|
|
|
31958
31866
|
this.config = config;
|
|
31959
31867
|
this.bufferSize = BUFFER_SIZE;
|
|
31960
31868
|
this.loader = isDataURL(this.path) ?
|
|
31961
|
-
new DataBuffer(this.path) :
|
|
31869
|
+
new DataBuffer(decodeDataURI$1(this.path).buffer) :
|
|
31870
|
+
igvxhr;
|
|
31962
31871
|
|
|
31963
|
-
|
|
31964
|
-
|
|
31872
|
+
const trixURL = config.trixURL || config.searchTrix;
|
|
31873
|
+
if (trixURL) {
|
|
31874
|
+
this._trix = new Trix(`${trixURL}x`, trixURL);
|
|
31965
31875
|
}
|
|
31966
31876
|
|
|
31967
31877
|
}
|
|
31968
31878
|
|
|
31879
|
+
/**
|
|
31880
|
+
* Preload all the data for this bb file
|
|
31881
|
+
* @returns {Promise<void>}
|
|
31882
|
+
*/
|
|
31883
|
+
async preload() {
|
|
31884
|
+
const data = await igvxhr.loadArrayBuffer(this.path);
|
|
31885
|
+
this.loader = new DataBuffer(data);
|
|
31886
|
+
}
|
|
31887
|
+
|
|
31969
31888
|
async readWGFeatures(bpPerPixel, windowFunction) {
|
|
31970
31889
|
await this.loadHeader();
|
|
31971
31890
|
const chrIdx1 = 0;
|
|
@@ -32631,8 +32550,8 @@ function decodeZoomData(data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, ch
|
|
|
32631
32550
|
|
|
32632
32551
|
class DataBuffer {
|
|
32633
32552
|
|
|
32634
|
-
constructor(
|
|
32635
|
-
this.data =
|
|
32553
|
+
constructor(data) {
|
|
32554
|
+
this.data = data;
|
|
32636
32555
|
}
|
|
32637
32556
|
|
|
32638
32557
|
/**
|
|
@@ -38019,6 +37938,16 @@ class Hub {
|
|
|
38019
37938
|
const groupsTxtURL = baseURL + genome.getProperty("groups");
|
|
38020
37939
|
groups = await loadStanzas(groupsTxtURL);
|
|
38021
37940
|
}
|
|
37941
|
+
|
|
37942
|
+
// If the genome has a chromSizes file, and it is not too large, set the chromSizesURL property. This will
|
|
37943
|
+
// enable whole genome view and the chromosome pulldown
|
|
37944
|
+
if (genome.hasProperty("chromSizes")) {
|
|
37945
|
+
const chromSizesURL = baseURL + genome.getProperty("chromSizes");
|
|
37946
|
+
const l = await getContentLength(chromSizesURL);
|
|
37947
|
+
if (l !== null && Number.parseInt(l) < 1000000) {
|
|
37948
|
+
genome.setProperty("chromSizesURL", chromSizesURL);
|
|
37949
|
+
}
|
|
37950
|
+
}
|
|
38022
37951
|
}
|
|
38023
37952
|
|
|
38024
37953
|
// TODO -- categorize extra "user" supplied and other tracks in some distinctive way before including them
|
|
@@ -38121,10 +38050,15 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
|
|
|
38121
38050
|
name: name,
|
|
38122
38051
|
twoBitURL: this.baseURL + this.genomeStanza.getProperty("twoBitPath"),
|
|
38123
38052
|
nameSet: "ucsc",
|
|
38124
|
-
wholeGenomeView: false,
|
|
38125
|
-
showChromosomeWidget: false
|
|
38126
38053
|
};
|
|
38127
38054
|
|
|
38055
|
+
if (this.genomeStanza.hasProperty("chromSizesURL")) {
|
|
38056
|
+
config.chromSizesURL = this.genomeStanza.getProperty("chromSizesURL");
|
|
38057
|
+
} else {
|
|
38058
|
+
config.wholeGenomeView = false;
|
|
38059
|
+
config.showChromosomeWidget = false;
|
|
38060
|
+
}
|
|
38061
|
+
|
|
38128
38062
|
if (this.genomeStanza.hasProperty("defaultPos")) {
|
|
38129
38063
|
const hubLocus = this.genomeStanza.getProperty("defaultPos");
|
|
38130
38064
|
// Strip out coordinates => whole chromosome view
|
|
@@ -38325,7 +38259,7 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
|
|
|
38325
38259
|
config.searchIndex = t.getProperty("searchIndex");
|
|
38326
38260
|
}
|
|
38327
38261
|
if (t.hasProperty("searchTrix")) {
|
|
38328
|
-
config.
|
|
38262
|
+
config.trixURL = this.baseURL + t.getProperty("searchTrix");
|
|
38329
38263
|
}
|
|
38330
38264
|
|
|
38331
38265
|
if (t.hasProperty("group")) {
|
|
@@ -38412,6 +38346,26 @@ class Stanza {
|
|
|
38412
38346
|
}
|
|
38413
38347
|
}
|
|
38414
38348
|
|
|
38349
|
+
|
|
38350
|
+
/**
|
|
38351
|
+
* Return the content length of the resource. If the content length cannot be determined return null;
|
|
38352
|
+
* @param url
|
|
38353
|
+
* @returns {Promise<number|string>}
|
|
38354
|
+
*/
|
|
38355
|
+
async function getContentLength(url) {
|
|
38356
|
+
try {
|
|
38357
|
+
const response = await fetch(url, {method: 'HEAD'});
|
|
38358
|
+
const headers = response.headers;
|
|
38359
|
+
if (headers.has("content-length")) {
|
|
38360
|
+
return headers.get("content-length")
|
|
38361
|
+
} else {
|
|
38362
|
+
return null
|
|
38363
|
+
}
|
|
38364
|
+
} catch (e) {
|
|
38365
|
+
return null
|
|
38366
|
+
}
|
|
38367
|
+
}
|
|
38368
|
+
|
|
38415
38369
|
/**
|
|
38416
38370
|
* Parse a UCSC file
|
|
38417
38371
|
* @param url
|
|
@@ -41960,7 +41914,7 @@ const hideAllMenuPopups = parent => {
|
|
|
41960
41914
|
|
|
41961
41915
|
class NavbarButton {
|
|
41962
41916
|
|
|
41963
|
-
constructor(
|
|
41917
|
+
constructor(parent, browser, title, buttonLabel, imageSVG, imageHoverSVG, initialButtonState) {
|
|
41964
41918
|
|
|
41965
41919
|
this.browser = browser;
|
|
41966
41920
|
|
|
@@ -42017,7 +41971,7 @@ class NavbarButton {
|
|
|
42017
41971
|
}
|
|
42018
41972
|
|
|
42019
41973
|
configureTextButton(textContent) {
|
|
42020
|
-
|
|
41974
|
+
console.log(`text ${this.title}`);
|
|
42021
41975
|
this.button.classList.add('igv-navbar-text-button');
|
|
42022
41976
|
|
|
42023
41977
|
const tempDiv = document.createElement('div');
|
|
@@ -42032,6 +41986,7 @@ class NavbarButton {
|
|
|
42032
41986
|
}
|
|
42033
41987
|
|
|
42034
41988
|
configureIconButton() {
|
|
41989
|
+
console.log(`icon ${this.title}`);
|
|
42035
41990
|
this.button.classList.add('igv-navbar-icon-button');
|
|
42036
41991
|
}
|
|
42037
41992
|
|
|
@@ -42071,11 +42026,6 @@ class NavbarButton {
|
|
|
42071
42026
|
this.hide();
|
|
42072
42027
|
}
|
|
42073
42028
|
}
|
|
42074
|
-
|
|
42075
|
-
static currentNavbarButtonClass(browser) {
|
|
42076
|
-
const el = browser.$navigation.get(0).querySelector('.igv-navbar-text-button');
|
|
42077
|
-
return el ? 'igv-navbar-text-button' : 'igv-navbar-icon-button'
|
|
42078
|
-
}
|
|
42079
42029
|
}
|
|
42080
42030
|
|
|
42081
42031
|
const overlayTrackImage =
|
|
@@ -42284,6 +42234,19 @@ class MergedTrack extends TrackBase {
|
|
|
42284
42234
|
return this._autoscale
|
|
42285
42235
|
}
|
|
42286
42236
|
|
|
42237
|
+
set autoscaleGroup(g) {
|
|
42238
|
+
if(this.tracks) {
|
|
42239
|
+
for(let t of this.tracks) t.autoscaleGroup = g;
|
|
42240
|
+
}
|
|
42241
|
+
}
|
|
42242
|
+
|
|
42243
|
+
get autoscaleGroup() {
|
|
42244
|
+
if(this.tracks && this.tracks.length > 0) {
|
|
42245
|
+
const g = this.tracks[0].autoscaleGroup;
|
|
42246
|
+
return (this.tracks.some(t => g !== t.autoscaleGroup)) ? undefined : g
|
|
42247
|
+
}
|
|
42248
|
+
}
|
|
42249
|
+
|
|
42287
42250
|
/**
|
|
42288
42251
|
* Set the data range of all constitutive numeric tracks. This method is called from the menu item, i.e. an explicit
|
|
42289
42252
|
* setting, so it should disable autoscale as well.
|
|
@@ -42648,9 +42611,9 @@ const numericTracks = (tracks) => {
|
|
|
42648
42611
|
};
|
|
42649
42612
|
|
|
42650
42613
|
class OverlayTrackButton extends NavbarButton {
|
|
42651
|
-
constructor(
|
|
42614
|
+
constructor(parent, browser) {
|
|
42652
42615
|
|
|
42653
|
-
super(
|
|
42616
|
+
super(parent, browser, 'Overlay Tracks', buttonLabel, overlayTrackImage, overlayTrackImageHover, false);
|
|
42654
42617
|
|
|
42655
42618
|
this.button.addEventListener('mouseenter', () => this.setState(true));
|
|
42656
42619
|
this.button.addEventListener('mouseleave', () => this.setState(false));
|
|
@@ -42673,15 +42636,15 @@ function trackOverlayClickHandler(e) {
|
|
|
42673
42636
|
|
|
42674
42637
|
if (true === isOverlayTrackCriteriaMet(this.browser)) {
|
|
42675
42638
|
|
|
42676
|
-
const tracks = this.browser.getSelectedTrackViews().map(({
|
|
42639
|
+
const tracks = this.browser.getSelectedTrackViews().map(({track}) => track);
|
|
42677
42640
|
for (const track of tracks) {
|
|
42678
42641
|
track.selected = false;
|
|
42679
42642
|
}
|
|
42680
42643
|
|
|
42681
|
-
// Flatten any merged tracks. Must do this before
|
|
42644
|
+
// Flatten any merged tracks. Must do this before their removal
|
|
42682
42645
|
const flattenedTracks = [];
|
|
42683
|
-
for(let t of tracks) {
|
|
42684
|
-
if("merged" === t.type) {
|
|
42646
|
+
for (let t of tracks) {
|
|
42647
|
+
if ("merged" === t.type) {
|
|
42685
42648
|
flattenedTracks.push(...t.tracks);
|
|
42686
42649
|
} else {
|
|
42687
42650
|
flattenedTracks.push(t);
|
|
@@ -42694,17 +42657,20 @@ function trackOverlayClickHandler(e) {
|
|
|
42694
42657
|
type: 'merged',
|
|
42695
42658
|
autoscale: false,
|
|
42696
42659
|
alpha: 0.5, //fudge * (1.0/tracks.length),
|
|
42697
|
-
height: Math.max(...tracks.map(({
|
|
42698
|
-
order: Math.min(...tracks.map(({
|
|
42660
|
+
height: Math.max(...tracks.map(({height}) => height)),
|
|
42661
|
+
order: Math.min(...tracks.map(({order}) => order)),
|
|
42699
42662
|
};
|
|
42700
42663
|
|
|
42701
42664
|
const mergedTrack = new MergedTrack(config, this.browser, flattenedTracks);
|
|
42702
42665
|
|
|
42703
42666
|
for (const track of tracks) {
|
|
42704
|
-
this.browser.
|
|
42667
|
+
const idx = this.browser.trackViews.indexOf(track.trackView);
|
|
42668
|
+
this.browser.trackViews.splice(idx, 1);
|
|
42669
|
+
track.trackView.dispose();
|
|
42705
42670
|
}
|
|
42706
42671
|
|
|
42707
42672
|
this.browser.addTrack(config, mergedTrack);
|
|
42673
|
+
mergedTrack.trackView.updateViews();
|
|
42708
42674
|
|
|
42709
42675
|
}
|
|
42710
42676
|
|
|
@@ -42716,9 +42682,9 @@ function isOverlayTrackCriteriaMet(browser) {
|
|
|
42716
42682
|
|
|
42717
42683
|
if (selected && selected.length > 1) {
|
|
42718
42684
|
|
|
42719
|
-
const criteriaSet = new Set([
|
|
42685
|
+
const criteriaSet = new Set(['wig', 'merged']);
|
|
42720
42686
|
|
|
42721
|
-
const list = selected.filter(({
|
|
42687
|
+
const list = selected.filter(({track}) => criteriaSet.has(track.type));
|
|
42722
42688
|
|
|
42723
42689
|
return list.length > 1
|
|
42724
42690
|
|
|
@@ -42833,6 +42799,8 @@ class TrackView {
|
|
|
42833
42799
|
createAxis(browser, track) {
|
|
42834
42800
|
|
|
42835
42801
|
const axis = div();
|
|
42802
|
+
this.axis = axis;
|
|
42803
|
+
|
|
42836
42804
|
browser.columnContainer.querySelector('.igv-axis-column').appendChild(axis);
|
|
42837
42805
|
|
|
42838
42806
|
axis.dataset.tracktype = track.type;
|
|
@@ -42850,12 +42818,12 @@ class TrackView {
|
|
|
42850
42818
|
|
|
42851
42819
|
if (false === multiTrackSelectExclusionTypes.has(this.track.type)) {
|
|
42852
42820
|
|
|
42853
|
-
|
|
42854
|
-
axis.appendChild(trackSelectionContainer);
|
|
42821
|
+
this.trackSelectionContainer = div();
|
|
42822
|
+
axis.appendChild(this.trackSelectionContainer);
|
|
42855
42823
|
|
|
42856
42824
|
const html = `<input type="checkbox" name="track-select">`;
|
|
42857
42825
|
const input = document.createRange().createContextualFragment(html).firstChild;
|
|
42858
|
-
trackSelectionContainer.appendChild(input);
|
|
42826
|
+
this.trackSelectionContainer.appendChild(input);
|
|
42859
42827
|
input.checked = this.track.selected || false;
|
|
42860
42828
|
|
|
42861
42829
|
input.addEventListener('change', event => {
|
|
@@ -42863,10 +42831,10 @@ class TrackView {
|
|
|
42863
42831
|
event.stopPropagation();
|
|
42864
42832
|
this.track.selected = event.target.checked;
|
|
42865
42833
|
this.setDragHandleSelectionState(event.target.checked);
|
|
42866
|
-
this.browser.overlayTrackButton.setVisibility(
|
|
42834
|
+
this.browser.overlayTrackButton.setVisibility(isOverlayTrackCriteriaMet(this.browser));
|
|
42867
42835
|
});
|
|
42868
42836
|
|
|
42869
|
-
this.
|
|
42837
|
+
this.enableTrackSelection(false);
|
|
42870
42838
|
|
|
42871
42839
|
}
|
|
42872
42840
|
|
|
@@ -43676,13 +43644,19 @@ class TrackView {
|
|
|
43676
43644
|
return Math.max(...this.viewports.map(viewport => viewport.getContentHeight()))
|
|
43677
43645
|
}
|
|
43678
43646
|
|
|
43679
|
-
|
|
43647
|
+
enableTrackSelection(doEnableMultiSelection) {
|
|
43680
43648
|
|
|
43681
|
-
const container =
|
|
43649
|
+
const container = this.trackSelectionContainer;
|
|
43650
|
+
|
|
43651
|
+
if (!container || multiTrackSelectExclusionTypes.has(this.track.type)) {
|
|
43652
|
+
return
|
|
43653
|
+
}
|
|
43682
43654
|
|
|
43683
43655
|
if (false !== doEnableMultiSelection) {
|
|
43684
43656
|
container.style.display = 'grid';
|
|
43685
43657
|
} else {
|
|
43658
|
+
// If disabling selection set track selection state to false
|
|
43659
|
+
this.track.selected = false;
|
|
43686
43660
|
|
|
43687
43661
|
const trackSelectInput = container.querySelector('[name=track-select]');
|
|
43688
43662
|
trackSelectInput.checked = this.track.selected;
|
|
@@ -43708,13 +43682,11 @@ class TrackView {
|
|
|
43708
43682
|
dragHandle.classList.remove('igv-track-drag-handle-selected-color');
|
|
43709
43683
|
dragHandle.classList.add('igv-track-drag-handle-color');
|
|
43710
43684
|
}
|
|
43711
|
-
|
|
43712
43685
|
}
|
|
43713
43686
|
|
|
43714
43687
|
}
|
|
43715
43688
|
|
|
43716
43689
|
|
|
43717
|
-
|
|
43718
43690
|
function renderSVGAxis(context, track, axisCanvas, deltaX, deltaY) {
|
|
43719
43691
|
|
|
43720
43692
|
if (typeof track.paintAxis === 'function') {
|
|
@@ -43828,13 +43800,13 @@ class ConstantColorScale {
|
|
|
43828
43800
|
*
|
|
43829
43801
|
*/
|
|
43830
43802
|
|
|
43831
|
-
const defaultColorScaleConfig = {threshold: 2000, r: 0, g: 0, b: 255};
|
|
43803
|
+
const defaultColorScaleConfig$1 = {threshold: 2000, r: 0, g: 0, b: 255};
|
|
43832
43804
|
|
|
43833
43805
|
class HicColorScale {
|
|
43834
43806
|
|
|
43835
43807
|
constructor(scale) {
|
|
43836
43808
|
|
|
43837
|
-
scale = scale || defaultColorScaleConfig;
|
|
43809
|
+
scale = scale || defaultColorScaleConfig$1;
|
|
43838
43810
|
this.threshold = scale.threshold;
|
|
43839
43811
|
this.r = scale.r;
|
|
43840
43812
|
this.g = scale.g;
|
|
@@ -54037,6 +54009,10 @@ async function inferFileFormatFromContents(config) {
|
|
|
54037
54009
|
if (firstLine.startsWith("##gff-version")) {
|
|
54038
54010
|
return "gff"
|
|
54039
54011
|
}
|
|
54012
|
+
if(firstLine.startsWith("##fileformat=")) {
|
|
54013
|
+
return firstLine.substring(13).toLowerCase(); // Non standard extension of VCF convention
|
|
54014
|
+
}
|
|
54015
|
+
|
|
54040
54016
|
|
|
54041
54017
|
// QTL test must preceed GWAS test as GWAS files will also pass the QTL test
|
|
54042
54018
|
if (QTLParser.isQTL(firstLine)) {
|
|
@@ -57273,10 +57249,6 @@ class AlignmentTrack extends TrackBase {
|
|
|
57273
57249
|
|
|
57274
57250
|
function clickHandler() {
|
|
57275
57251
|
this.alignmentTrack.colorBy = menuItem.key;
|
|
57276
|
-
if ('strand' !== this.alignmentTrack.groupBy) {
|
|
57277
|
-
this.alignmentTrack.groupBy = 'strand';
|
|
57278
|
-
this.alignmentTrack.repackAlignments();
|
|
57279
|
-
}
|
|
57280
57252
|
this.trackView.repaintViews();
|
|
57281
57253
|
}
|
|
57282
57254
|
|
|
@@ -67865,6 +67837,7 @@ async function searchFeatures(browser, name) {
|
|
|
67865
67837
|
const searchConfig = browser.searchConfig || DEFAULT_SEARCH_CONFIG;
|
|
67866
67838
|
let feature;
|
|
67867
67839
|
|
|
67840
|
+
name = name.toUpperCase();
|
|
67868
67841
|
const searchableTracks = browser.tracks.filter(t => t.searchable);
|
|
67869
67842
|
for (let track of searchableTracks) {
|
|
67870
67843
|
const feature = await track.search(name);
|
|
@@ -70203,6 +70176,343 @@ class SpliceJunctionTrack extends TrackBase {
|
|
|
70203
70176
|
}
|
|
70204
70177
|
}
|
|
70205
70178
|
|
|
70179
|
+
/*
|
|
70180
|
+
* The MIT License (MIT)
|
|
70181
|
+
*
|
|
70182
|
+
* Copyright (c) 2016-2017 The Regents of the University of California
|
|
70183
|
+
*
|
|
70184
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
70185
|
+
* associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
70186
|
+
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
70187
|
+
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
70188
|
+
* following conditions:
|
|
70189
|
+
*
|
|
70190
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
70191
|
+
* portions of the Software.
|
|
70192
|
+
*
|
|
70193
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
70194
|
+
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
70195
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
70196
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
70197
|
+
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
70198
|
+
* THE SOFTWARE.
|
|
70199
|
+
*
|
|
70200
|
+
*/
|
|
70201
|
+
|
|
70202
|
+
const defaultColorScaleConfig = {min: 0, max: 3000, color: "rgb(0,0,255)"};
|
|
70203
|
+
|
|
70204
|
+
class ShoeboxColorScale {
|
|
70205
|
+
|
|
70206
|
+
constructor(scale) {
|
|
70207
|
+
|
|
70208
|
+
scale = scale || defaultColorScaleConfig;
|
|
70209
|
+
this.max = scale.max;
|
|
70210
|
+
this.min = scale.min || 0;
|
|
70211
|
+
this.cache = [];
|
|
70212
|
+
this.nbins = 1000;
|
|
70213
|
+
this.binsize = (this.max - this.min) / this.nbins;
|
|
70214
|
+
this.updateColor(scale.color || "rgb(0,0,255)");
|
|
70215
|
+
|
|
70216
|
+
}
|
|
70217
|
+
|
|
70218
|
+
updateColor(color) {
|
|
70219
|
+
const comps = color.substring(4).replace(")", "").split(",");
|
|
70220
|
+
if (comps.length === 3) {
|
|
70221
|
+
this.r = Number.parseInt(comps[0].trim());
|
|
70222
|
+
this.g = Number.parseInt(comps[1].trim());
|
|
70223
|
+
this.b = Number.parseInt(comps[2].trim());
|
|
70224
|
+
}
|
|
70225
|
+
this.cache = [];
|
|
70226
|
+
}
|
|
70227
|
+
|
|
70228
|
+
setMinMax(min, max) {
|
|
70229
|
+
this.min = min;
|
|
70230
|
+
this.max = max;
|
|
70231
|
+
this.cache = [];
|
|
70232
|
+
this.binsize = (this.max - this.min) / this.nbins;
|
|
70233
|
+
}
|
|
70234
|
+
|
|
70235
|
+
getColor(value) {
|
|
70236
|
+
const low = 0;
|
|
70237
|
+
if (value < this.min) return "white"
|
|
70238
|
+
|
|
70239
|
+
const bin = Math.floor((Math.min(this.max, value) - this.min) / this.binsize);
|
|
70240
|
+
if (undefined === this.cache[bin]) {
|
|
70241
|
+
const alpha = (IGVMath.clamp(value, low, this.max) - low) / (this.max - low);
|
|
70242
|
+
this.cache[bin] = `rgba(${this.r},${this.g},${this.b}, ${alpha})`;
|
|
70243
|
+
}
|
|
70244
|
+
return this.cache[bin]
|
|
70245
|
+
}
|
|
70246
|
+
|
|
70247
|
+
/**
|
|
70248
|
+
*
|
|
70249
|
+
* @returns {{min: (*|number), color: string, max}}
|
|
70250
|
+
*/
|
|
70251
|
+
toJson() {
|
|
70252
|
+
return {
|
|
70253
|
+
min: this.min,
|
|
70254
|
+
max: this.max,
|
|
70255
|
+
color: `rgb(${this.r},${this.g},${this.b})`
|
|
70256
|
+
}
|
|
70257
|
+
}
|
|
70258
|
+
|
|
70259
|
+
// For short-term backward compatibility
|
|
70260
|
+
static parse(str) {
|
|
70261
|
+
|
|
70262
|
+
const tokens = str.split(",");
|
|
70263
|
+
|
|
70264
|
+
const cs = {
|
|
70265
|
+
min: Number.parseFloat(tokens[0]),
|
|
70266
|
+
max: Number.parseFloat(tokens[1]),
|
|
70267
|
+
color: `${tokens[2]},${tokens[3]},${tokens[4]}`
|
|
70268
|
+
};
|
|
70269
|
+
return new ShoeboxColorScale(cs)
|
|
70270
|
+
}
|
|
70271
|
+
|
|
70272
|
+
}
|
|
70273
|
+
|
|
70274
|
+
class ShoeboxTrack extends TrackBase {
|
|
70275
|
+
|
|
70276
|
+
static defaults = {
|
|
70277
|
+
height: 300,
|
|
70278
|
+
rowHeight: 3,
|
|
70279
|
+
max: 3000,
|
|
70280
|
+
visibilityWindow: 10000
|
|
70281
|
+
}
|
|
70282
|
+
|
|
70283
|
+
constructor(config, browser) {
|
|
70284
|
+
super(config, browser);
|
|
70285
|
+
}
|
|
70286
|
+
|
|
70287
|
+
init(config) {
|
|
70288
|
+
super.init(config);
|
|
70289
|
+
|
|
70290
|
+
this.type = "shoebox";
|
|
70291
|
+
this.height = config.height || 300;
|
|
70292
|
+
this.rowHeight = config.rowHeight || 3;
|
|
70293
|
+
this.max = config.max || 3000;
|
|
70294
|
+
|
|
70295
|
+
// Hardcoded -- todo get from track line
|
|
70296
|
+
this.sampleKeys = [];
|
|
70297
|
+
for (let i = 1; i <= 100; i++) {
|
|
70298
|
+
this.sampleKeys.push(i);
|
|
70299
|
+
}
|
|
70300
|
+
|
|
70301
|
+
// Create featureSource
|
|
70302
|
+
const configCopy = Object.assign({}, this.config);
|
|
70303
|
+
configCopy.format = 'shoebox'; // bit of a hack
|
|
70304
|
+
this.featureSource = FeatureSource(configCopy, this.browser.genome);
|
|
70305
|
+
}
|
|
70306
|
+
|
|
70307
|
+
async postInit() {
|
|
70308
|
+
if (typeof this.featureSource.getHeader === "function") {
|
|
70309
|
+
this.header = await this.featureSource.getHeader();
|
|
70310
|
+
if (this.disposed) return // This track was removed during async load
|
|
70311
|
+
}
|
|
70312
|
+
// Set properties from track line
|
|
70313
|
+
if (this.header) {
|
|
70314
|
+
this.setTrackProperties(this.header);
|
|
70315
|
+
}
|
|
70316
|
+
|
|
70317
|
+
// Must do the following after setting track properties as they can be overriden via a track line
|
|
70318
|
+
|
|
70319
|
+
// Color settings
|
|
70320
|
+
if (this.config.colorScale && this.config.colorScale.max && this.config.colorScale.color) { // Minimal validation
|
|
70321
|
+
this.colorScale = new ShoeboxColorScale(this.config.colorScale);
|
|
70322
|
+
|
|
70323
|
+
} else {
|
|
70324
|
+
const min = this.dataRange.min;
|
|
70325
|
+
const max = this.dataRange.max;
|
|
70326
|
+
this.colorScale = new ShoeboxColorScale({min, max, color: this.color});
|
|
70327
|
+
}
|
|
70328
|
+
}
|
|
70329
|
+
|
|
70330
|
+
get color() {
|
|
70331
|
+
return this._color || "rgb(0,0,255)"
|
|
70332
|
+
}
|
|
70333
|
+
|
|
70334
|
+
set color(color) {
|
|
70335
|
+
this._color = color;
|
|
70336
|
+
if (this.colorScale) {
|
|
70337
|
+
this.colorScale.updateColor(color);
|
|
70338
|
+
}
|
|
70339
|
+
}
|
|
70340
|
+
|
|
70341
|
+
menuItemList() {
|
|
70342
|
+
|
|
70343
|
+
const menuItems = [];
|
|
70344
|
+
|
|
70345
|
+
|
|
70346
|
+
menuItems.push('<hr/>');
|
|
70347
|
+
|
|
70348
|
+
// Data range
|
|
70349
|
+
let object = $$1('<div>');
|
|
70350
|
+
object.text('Set data range');
|
|
70351
|
+
|
|
70352
|
+
function dialogPresentationHandler() {
|
|
70353
|
+
|
|
70354
|
+
if (this.trackView.track.selected) {
|
|
70355
|
+
this.browser.dataRangeDialog.configure(this.trackView.browser.getSelectedTrackViews());
|
|
70356
|
+
} else {
|
|
70357
|
+
this.browser.dataRangeDialog.configure(this.trackView);
|
|
70358
|
+
}
|
|
70359
|
+
this.browser.dataRangeDialog.present($$1(this.browser.columnContainer));
|
|
70360
|
+
}
|
|
70361
|
+
|
|
70362
|
+
menuItems.push({object, dialog: dialogPresentationHandler});
|
|
70363
|
+
|
|
70364
|
+
return menuItems
|
|
70365
|
+
}
|
|
70366
|
+
|
|
70367
|
+
setDataRange({min, max}) {
|
|
70368
|
+
this.dataRange.min = min;
|
|
70369
|
+
this.dataRange.max = max;
|
|
70370
|
+
this.colorScale.min = min;
|
|
70371
|
+
this.colorScale.max = max;
|
|
70372
|
+
this.trackView.repaintViews();
|
|
70373
|
+
}
|
|
70374
|
+
|
|
70375
|
+
hasSamples() {
|
|
70376
|
+
return true // by definition
|
|
70377
|
+
}
|
|
70378
|
+
|
|
70379
|
+
getSamples() {
|
|
70380
|
+
return {
|
|
70381
|
+
names: this.sampleKeys,
|
|
70382
|
+
height: this.rowHeight,
|
|
70383
|
+
yOffset: 0
|
|
70384
|
+
}
|
|
70385
|
+
}
|
|
70386
|
+
|
|
70387
|
+
async getFeatures(chr, start, end, bpPerPixel) {
|
|
70388
|
+
const visibilityWindow = this.visibilityWindow;
|
|
70389
|
+
return this.featureSource.getFeatures({chr, start, end, bpPerPixel, visibilityWindow})
|
|
70390
|
+
}
|
|
70391
|
+
|
|
70392
|
+
|
|
70393
|
+
draw({context, pixelTop, pixelWidth, pixelHeight, features, bpPerPixel, bpStart}) {
|
|
70394
|
+
|
|
70395
|
+
|
|
70396
|
+
IGVGraphics.fillRect(context, 0, pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
70397
|
+
|
|
70398
|
+
if (features && features.length > 0) {
|
|
70399
|
+
|
|
70400
|
+
const rowHeight = this.rowHeight;
|
|
70401
|
+
const pixelBottom = pixelTop + pixelHeight;
|
|
70402
|
+
const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
|
|
70403
|
+
|
|
70404
|
+
const h = rowHeight;
|
|
70405
|
+
|
|
70406
|
+
for (let f of features) {
|
|
70407
|
+
|
|
70408
|
+
// Test for overlap with in-view region
|
|
70409
|
+
if (f.end < bpStart || f.start > bpEnd) continue
|
|
70410
|
+
|
|
70411
|
+
// Pixel x values
|
|
70412
|
+
const xLeft = Math.round((f.start - bpStart) / bpPerPixel);
|
|
70413
|
+
const xRight = Math.round((f.end - bpStart) / bpPerPixel);
|
|
70414
|
+
const w = Math.max(1, xRight - xLeft);
|
|
70415
|
+
|
|
70416
|
+
// Loop through value array
|
|
70417
|
+
let row = 0;
|
|
70418
|
+
|
|
70419
|
+
for (let i = f.values.length - 1; i >= 0; i--) {
|
|
70420
|
+
|
|
70421
|
+
const v = f.values[i];
|
|
70422
|
+
|
|
70423
|
+
const y = row * rowHeight;
|
|
70424
|
+
|
|
70425
|
+
|
|
70426
|
+
const bottom = y + rowHeight;
|
|
70427
|
+
|
|
70428
|
+
if (bottom < pixelTop || y > pixelBottom) {
|
|
70429
|
+
continue
|
|
70430
|
+
}
|
|
70431
|
+
|
|
70432
|
+
const color = this.colorScale.getColor(v);
|
|
70433
|
+
|
|
70434
|
+
context.fillStyle = color;
|
|
70435
|
+
|
|
70436
|
+
context.fillRect(xLeft, y, w, h);
|
|
70437
|
+
|
|
70438
|
+
row++;
|
|
70439
|
+
}
|
|
70440
|
+
}
|
|
70441
|
+
}
|
|
70442
|
+
|
|
70443
|
+
}
|
|
70444
|
+
|
|
70445
|
+
/**
|
|
70446
|
+
* Optional method to compute pixel height to accomodate the list of features.
|
|
70447
|
+
*
|
|
70448
|
+
* @param features
|
|
70449
|
+
* @returns {number}
|
|
70450
|
+
*/
|
|
70451
|
+
computePixelHeight(features) {
|
|
70452
|
+
if (!features || features.length === 0) return 0
|
|
70453
|
+
return features[0].values.length * this.rowHeight
|
|
70454
|
+
}
|
|
70455
|
+
|
|
70456
|
+
|
|
70457
|
+
clickedFeatures(clickState) {
|
|
70458
|
+
|
|
70459
|
+
const allFeatures = super.clickedFeatures(clickState);
|
|
70460
|
+
const y = clickState.y;
|
|
70461
|
+
return allFeatures.filter(function (feature) {
|
|
70462
|
+
const rect = feature.pixelRect;
|
|
70463
|
+
return rect && y >= rect.y && y <= (rect.y + rect.h)
|
|
70464
|
+
})
|
|
70465
|
+
|
|
70466
|
+
}
|
|
70467
|
+
|
|
70468
|
+
hoverText(clickState) {
|
|
70469
|
+
const features = this.clickedFeatures(clickState);
|
|
70470
|
+
if (features && features.length > 0) {
|
|
70471
|
+
return `${features[0].sample}: ${features[0].value}`
|
|
70472
|
+
}
|
|
70473
|
+
}
|
|
70474
|
+
|
|
70475
|
+
popupData(clickState, featureList) {
|
|
70476
|
+
|
|
70477
|
+
if (featureList === undefined) featureList = this.clickedFeatures(clickState);
|
|
70478
|
+
|
|
70479
|
+
const items = [];
|
|
70480
|
+
|
|
70481
|
+
for (let feature of featureList) {
|
|
70482
|
+
|
|
70483
|
+
// Double line divider between features
|
|
70484
|
+
if (items.length > 0) {
|
|
70485
|
+
items.push('<hr/>');
|
|
70486
|
+
items.push('<hr/>');
|
|
70487
|
+
}
|
|
70488
|
+
|
|
70489
|
+
// hack for whole genome features, which save the original feature as "_f"
|
|
70490
|
+
const f = feature._f || feature;
|
|
70491
|
+
|
|
70492
|
+
const data = (typeof f.popupData === 'function') ?
|
|
70493
|
+
f.popupData(this.type, this.browser.genome.id) :
|
|
70494
|
+
this.extractPopupData(f);
|
|
70495
|
+
Array.prototype.push.apply(items, data);
|
|
70496
|
+
|
|
70497
|
+
}
|
|
70498
|
+
|
|
70499
|
+
return items
|
|
70500
|
+
}
|
|
70501
|
+
|
|
70502
|
+
get supportsWholeGenome() {
|
|
70503
|
+
return false
|
|
70504
|
+
}
|
|
70505
|
+
|
|
70506
|
+
getState() {
|
|
70507
|
+
|
|
70508
|
+
const config = super.getState();
|
|
70509
|
+
config.colorScale = this.colorScale.toJson();
|
|
70510
|
+
return config
|
|
70511
|
+
|
|
70512
|
+
}
|
|
70513
|
+
|
|
70514
|
+
}
|
|
70515
|
+
|
|
70206
70516
|
//import CNVPytorTrack from "./CNVpytor/cnvpytorTrack.js"
|
|
70207
70517
|
|
|
70208
70518
|
|
|
@@ -70214,7 +70524,7 @@ const trackFunctions =
|
|
|
70214
70524
|
['seg', (config, browser) => new SegTrack(config, browser)],
|
|
70215
70525
|
['mut', (config, browser) => new SegTrack(config, browser)],
|
|
70216
70526
|
['maf', (config, browser) => new SegTrack(config, browser)],
|
|
70217
|
-
['shoebox', (config, browser) => new
|
|
70527
|
+
['shoebox', (config, browser) => new ShoeboxTrack(config, browser)],
|
|
70218
70528
|
['wig', (config, browser) => new WigTrack(config, browser)],
|
|
70219
70529
|
['merged', (config, browser) => new MergedTrack(config, browser)],
|
|
70220
70530
|
['alignment', (config, browser) => new BAMTrack(config, browser)],
|
|
@@ -70706,94 +71016,11 @@ function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, v
|
|
|
70706
71016
|
})
|
|
70707
71017
|
}
|
|
70708
71018
|
|
|
70709
|
-
const _version = "3.0.
|
|
71019
|
+
const _version = "3.0.9";
|
|
70710
71020
|
function version() {
|
|
70711
71021
|
return _version
|
|
70712
71022
|
}
|
|
70713
71023
|
|
|
70714
|
-
/*
|
|
70715
|
-
* The MIT License (MIT)
|
|
70716
|
-
*
|
|
70717
|
-
* Copyright (c) 2014 Broad Institute
|
|
70718
|
-
*
|
|
70719
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
70720
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
70721
|
-
* in the Software without restriction, including without limitation the rights
|
|
70722
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
70723
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
70724
|
-
* furnished to do so, subject to the following conditions:
|
|
70725
|
-
*
|
|
70726
|
-
* The above copyright notice and this permission notice shall be included in
|
|
70727
|
-
* all copies or substantial portions of the Software.
|
|
70728
|
-
*
|
|
70729
|
-
*
|
|
70730
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
70731
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
70732
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
70733
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
70734
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
70735
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
70736
|
-
* THE SOFTWARE.
|
|
70737
|
-
*/
|
|
70738
|
-
|
|
70739
|
-
const navbarResponsiveClasses = {};
|
|
70740
|
-
|
|
70741
|
-
const responsiveThreshold = 8;
|
|
70742
|
-
let textButtonContainerWidth = undefined;
|
|
70743
|
-
|
|
70744
|
-
function navbarDidResize(browser, width) {
|
|
70745
|
-
|
|
70746
|
-
const currentClass = NavbarButton.currentNavbarButtonClass(browser);
|
|
70747
|
-
if ('igv-navbar-text-button' === currentClass) {
|
|
70748
|
-
textButtonContainerWidth = browser.$navigation.get(0).querySelector('.igv-navbar-right-container').getBoundingClientRect().width;
|
|
70749
|
-
}
|
|
70750
|
-
|
|
70751
|
-
const responsiveClasses = getResponsiveClasses(browser, width);
|
|
70752
|
-
|
|
70753
|
-
$$1(browser.zoomWidget.zoomContainer).removeClass();
|
|
70754
|
-
$$1(browser.zoomWidget.zoomContainer).addClass(responsiveClasses.zoomContainer);
|
|
70755
|
-
|
|
70756
|
-
browser.fireEvent('navbar-resize', [ responsiveClasses.navbarButton ]);
|
|
70757
|
-
}
|
|
70758
|
-
|
|
70759
|
-
function getResponsiveClasses(browser, navbarWidth) {
|
|
70760
|
-
|
|
70761
|
-
const isWGV =
|
|
70762
|
-
(browser.isMultiLocusWholeGenomeView()) ||
|
|
70763
|
-
(browser.referenceFrameList && GenomeUtils.isWholeGenomeView(browser.referenceFrameList[0].chr));
|
|
70764
|
-
|
|
70765
|
-
isWGV ? browser.windowSizePanel.hide() : browser.windowSizePanel.show();
|
|
70766
|
-
|
|
70767
|
-
const { x: leftContainerX, width: leftContainerWidth } = browser.$navigation.get(0).querySelector('.igv-navbar-left-container').getBoundingClientRect();
|
|
70768
|
-
const leftContainerExtent = leftContainerX + leftContainerWidth;
|
|
70769
|
-
const { x:rightContainerX} = browser.$navigation.get(0).querySelector('.igv-navbar-right-container').getBoundingClientRect();
|
|
70770
|
-
|
|
70771
|
-
const delta = rightContainerX - leftContainerExtent;
|
|
70772
|
-
|
|
70773
|
-
const currentClass = NavbarButton.currentNavbarButtonClass(browser);
|
|
70774
|
-
|
|
70775
|
-
// console.log(`Current class ${ currentClass } Delta: ${ StringUtils.numberFormatter(Math.floor(delta))}`)
|
|
70776
|
-
|
|
70777
|
-
if ('igv-navbar-text-button' === currentClass && delta < responsiveThreshold) {
|
|
70778
|
-
navbarResponsiveClasses.navbarButton = 'igv-navbar-icon-button';
|
|
70779
|
-
} else if (textButtonContainerWidth && 'igv-navbar-icon-button' === currentClass) {
|
|
70780
|
-
const length = navbarWidth - leftContainerExtent;
|
|
70781
|
-
if (length - textButtonContainerWidth > responsiveThreshold) {
|
|
70782
|
-
navbarResponsiveClasses.navbarButton = 'igv-navbar-text-button';
|
|
70783
|
-
}
|
|
70784
|
-
|
|
70785
|
-
}
|
|
70786
|
-
|
|
70787
|
-
|
|
70788
|
-
if (isWGV) {
|
|
70789
|
-
navbarResponsiveClasses.zoomContainer = 'igv-zoom-widget-hidden';
|
|
70790
|
-
} else {
|
|
70791
|
-
navbarResponsiveClasses.zoomContainer = navbarWidth > 860 ? 'igv-zoom-widget' : 'igv-zoom-widget-900';
|
|
70792
|
-
}
|
|
70793
|
-
|
|
70794
|
-
return navbarResponsiveClasses
|
|
70795
|
-
}
|
|
70796
|
-
|
|
70797
71024
|
/*
|
|
70798
71025
|
* The MIT License (MIT)
|
|
70799
71026
|
*
|
|
@@ -70841,7 +71068,7 @@ class ChromosomeSelectWidget {
|
|
|
70841
71068
|
});
|
|
70842
71069
|
|
|
70843
71070
|
this.showAllChromosomes = browser.config.showAllChromosomes !== false; // i.e. default to true
|
|
70844
|
-
|
|
71071
|
+
this.genome = browser.genome;
|
|
70845
71072
|
}
|
|
70846
71073
|
|
|
70847
71074
|
show() {
|
|
@@ -70852,10 +71079,16 @@ class ChromosomeSelectWidget {
|
|
|
70852
71079
|
this.container.style.display = 'none';
|
|
70853
71080
|
}
|
|
70854
71081
|
|
|
71082
|
+
setValue(chrName) {
|
|
71083
|
+
this.select.value = this.genome.getChromosomeDisplayName(chrName);
|
|
71084
|
+
}
|
|
71085
|
+
|
|
70855
71086
|
update(genome) {
|
|
70856
71087
|
|
|
71088
|
+
this.genome = genome;
|
|
71089
|
+
|
|
70857
71090
|
// Start with explicit chromosome name list
|
|
70858
|
-
const list = genome.wgChromosomeNames || [];
|
|
71091
|
+
const list = genome.wgChromosomeNames.map(nm => genome.getChromosomeDisplayName(nm)) || [];
|
|
70859
71092
|
|
|
70860
71093
|
if (this.showAllChromosomes && genome.chromosomeNames.length > 1) {
|
|
70861
71094
|
const exclude = new Set(list);
|
|
@@ -70866,6 +71099,7 @@ class ChromosomeSelectWidget {
|
|
|
70866
71099
|
break
|
|
70867
71100
|
}
|
|
70868
71101
|
if (!exclude.has(nm)) {
|
|
71102
|
+
nm = genome.getChromosomeDisplayName(nm);
|
|
70869
71103
|
list.push(nm);
|
|
70870
71104
|
}
|
|
70871
71105
|
}
|
|
@@ -70946,6 +71180,99 @@ class WindowSizePanel {
|
|
|
70946
71180
|
}
|
|
70947
71181
|
}
|
|
70948
71182
|
|
|
71183
|
+
const multiSelectImage =
|
|
71184
|
+
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71185
|
+
<title>multi select</title>
|
|
71186
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71187
|
+
<g id="multi-select">
|
|
71188
|
+
<rect id="backdrop-copy-3" stroke="#737373" stroke-width="12" fill="#FFFFFF" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71189
|
+
<g id="row-copy-3" transform="translate(81, 427)" fill="#737373">
|
|
71190
|
+
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
71191
|
+
<rect id="Rectangle-Copy-16" stroke="#737373" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71192
|
+
</g>
|
|
71193
|
+
<g id="row-copy-2" transform="translate(82, 277)">
|
|
71194
|
+
<rect id="Rectangle" fill-opacity="0.33" fill="#CFCECE" x="133" y="0" width="329" height="70"></rect>
|
|
71195
|
+
<rect id="Rectangle-Copy-16" stroke-opacity="0.32659528" stroke="#CFCECE" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71196
|
+
</g>
|
|
71197
|
+
<g id="row-copy" transform="translate(81, 119)" fill="#737373">
|
|
71198
|
+
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
71199
|
+
<rect id="Rectangle-Copy-17" stroke="#737373" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71200
|
+
</g>
|
|
71201
|
+
</g>
|
|
71202
|
+
</g>
|
|
71203
|
+
</svg>`;
|
|
71204
|
+
|
|
71205
|
+
const multiSelectImageHover =
|
|
71206
|
+
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71207
|
+
<title>multi select hover</title>
|
|
71208
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71209
|
+
<g id="multi-select-hover">
|
|
71210
|
+
<rect id="backdrop-copy-4" stroke="#737373" stroke-width="12" fill="#737373" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71211
|
+
<g id="row-copy-3" transform="translate(81, 427)" fill="#FFFFFF">
|
|
71212
|
+
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
71213
|
+
<rect id="Rectangle-Copy-16" stroke="#FFFFFF" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71214
|
+
</g>
|
|
71215
|
+
<g id="row-copy-2" transform="translate(82, 277)">
|
|
71216
|
+
<rect id="Rectangle" fill-opacity="0.33" fill="#CFCECE" x="133" y="0" width="329" height="70"></rect>
|
|
71217
|
+
<rect id="Rectangle-Copy-16" stroke-opacity="0.33" stroke="#CFCECE" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71218
|
+
</g>
|
|
71219
|
+
<g id="row-copy" transform="translate(81, 119)" fill="#FFFFFF">
|
|
71220
|
+
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
71221
|
+
<rect id="Rectangle-Copy-17" stroke="#FFFFFF" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
71222
|
+
</g>
|
|
71223
|
+
</g>
|
|
71224
|
+
</g>
|
|
71225
|
+
</svg>`;
|
|
71226
|
+
|
|
71227
|
+
class MultiTrackSelectButton extends NavbarButton {
|
|
71228
|
+
|
|
71229
|
+
constructor(parent, browser, navbar, enableMultiTrackSelection) {
|
|
71230
|
+
|
|
71231
|
+
super(parent, browser, 'Select Tracks', buttonLabel, multiSelectImage, multiSelectImageHover, false);
|
|
71232
|
+
|
|
71233
|
+
this.navbar = navbar;
|
|
71234
|
+
this.enableMultiTrackSelection = false; // Initial state
|
|
71235
|
+
this.button.addEventListener('mouseenter', event => {
|
|
71236
|
+
if (false === enableMultiTrackSelection) {
|
|
71237
|
+
this.setState(true);
|
|
71238
|
+
}
|
|
71239
|
+
});
|
|
71240
|
+
|
|
71241
|
+
this.button.addEventListener('mouseleave', event => {
|
|
71242
|
+
if (false === enableMultiTrackSelection) {
|
|
71243
|
+
this.setState(false);
|
|
71244
|
+
}
|
|
71245
|
+
});
|
|
71246
|
+
|
|
71247
|
+
const mouseClickHandler = () => {
|
|
71248
|
+
// Toggle the selection state
|
|
71249
|
+
this.setMultiTrackSelection(!this.enableMultiTrackSelection);
|
|
71250
|
+
};
|
|
71251
|
+
|
|
71252
|
+
this.boundMouseClickHandler = mouseClickHandler.bind(this);
|
|
71253
|
+
|
|
71254
|
+
this.button.addEventListener('click', this.boundMouseClickHandler);
|
|
71255
|
+
|
|
71256
|
+
}
|
|
71257
|
+
|
|
71258
|
+
setMultiTrackSelection(enableMultiTrackSelection) {
|
|
71259
|
+
|
|
71260
|
+
this.enableMultiTrackSelection = enableMultiTrackSelection;
|
|
71261
|
+
this.setState(this.enableMultiTrackSelection);
|
|
71262
|
+
|
|
71263
|
+
// If enableMultiTrackSelection is false hide the Overly button
|
|
71264
|
+
if (false === this.enableMultiTrackSelection) {
|
|
71265
|
+
this.navbar.overlayTrackButton.setVisibility(false);
|
|
71266
|
+
}
|
|
71267
|
+
|
|
71268
|
+
for (const trackView of this.browser.trackViews) {
|
|
71269
|
+
trackView.enableTrackSelection(enableMultiTrackSelection);
|
|
71270
|
+
}
|
|
71271
|
+
|
|
71272
|
+
}
|
|
71273
|
+
|
|
71274
|
+
}
|
|
71275
|
+
|
|
70949
71276
|
class CursorGuide {
|
|
70950
71277
|
|
|
70951
71278
|
constructor(columnContainer, browser) {
|
|
@@ -71127,9 +71454,9 @@ const cursorImageHover =
|
|
|
71127
71454
|
|
|
71128
71455
|
class CursorGuideButton extends NavbarButton {
|
|
71129
71456
|
|
|
71130
|
-
constructor(
|
|
71457
|
+
constructor(parent, browser) {
|
|
71131
71458
|
|
|
71132
|
-
super(
|
|
71459
|
+
super(parent, browser, 'Crosshairs', buttonLabel, cursorImage, cursorImageHover, browser.doShowCursorGuide);
|
|
71133
71460
|
|
|
71134
71461
|
this.button.addEventListener('mouseenter', () => {
|
|
71135
71462
|
if (false === browser.doShowCursorGuide) {
|
|
@@ -71215,9 +71542,9 @@ const centerlineImageHover =
|
|
|
71215
71542
|
|
|
71216
71543
|
class CenterLineButton extends NavbarButton {
|
|
71217
71544
|
|
|
71218
|
-
constructor(
|
|
71545
|
+
constructor(parent, browser) {
|
|
71219
71546
|
|
|
71220
|
-
super(
|
|
71547
|
+
super(parent, browser, 'Center Line', buttonLabel, centerlineImage, centerlineImageHover, browser.config.showCenterGuide);
|
|
71221
71548
|
|
|
71222
71549
|
this.button.addEventListener('mouseenter', () => {
|
|
71223
71550
|
if (false === browser.doShowCenterLine) {
|
|
@@ -71306,7 +71633,7 @@ class TrackLabelControl extends NavbarButton {
|
|
|
71306
71633
|
|
|
71307
71634
|
constructor(parent, browser) {
|
|
71308
71635
|
|
|
71309
|
-
super(
|
|
71636
|
+
super(parent, browser, 'Track Labels', buttonLabel, trackLabelsImage, trackLabelsImageHover, browser.config.showTrackLabels);
|
|
71310
71637
|
|
|
71311
71638
|
this.button.addEventListener('mouseenter', () => {
|
|
71312
71639
|
if (false === browser.doShowTrackLabels) {
|
|
@@ -71336,28 +71663,28 @@ class TrackLabelControl extends NavbarButton {
|
|
|
71336
71663
|
|
|
71337
71664
|
}
|
|
71338
71665
|
|
|
71339
|
-
const
|
|
71666
|
+
const roiImage =
|
|
71340
71667
|
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71341
|
-
<title>
|
|
71668
|
+
<title>roi</title>
|
|
71342
71669
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71343
|
-
<g id="
|
|
71344
|
-
<rect id="Rectangle-Copy-
|
|
71345
|
-
<
|
|
71346
|
-
|
|
71347
|
-
|
|
71670
|
+
<g id="roi">
|
|
71671
|
+
<rect id="Rectangle-Copy-23" stroke="#737373" stroke-width="12" fill="#FFFFFF" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71672
|
+
<text id="ROI" font-family="HelveticaNeue-Bold, Helvetica Neue" font-size="258" font-weight="bold" fill="#737373">
|
|
71673
|
+
<tspan x="81.445" y="389">ROI</tspan>
|
|
71674
|
+
</text>
|
|
71348
71675
|
</g>
|
|
71349
71676
|
</g>
|
|
71350
71677
|
</svg>`;
|
|
71351
71678
|
|
|
71352
|
-
const
|
|
71679
|
+
const roiImageHover =
|
|
71353
71680
|
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71354
|
-
<title>
|
|
71681
|
+
<title>roi hover</title>
|
|
71355
71682
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71356
|
-
<g id="
|
|
71357
|
-
<rect id="Rectangle-Copy-
|
|
71358
|
-
<
|
|
71359
|
-
|
|
71360
|
-
|
|
71683
|
+
<g id="roi-hover">
|
|
71684
|
+
<rect id="Rectangle-Copy-24" stroke="#737373" stroke-width="12" fill="#737373" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71685
|
+
<text id="ROI" font-family="HelveticaNeue-Bold, Helvetica Neue" font-size="258" font-weight="bold" fill="#FFFFFF">
|
|
71686
|
+
<tspan x="81.445" y="389">ROI</tspan>
|
|
71687
|
+
</text>
|
|
71361
71688
|
</g>
|
|
71362
71689
|
</g>
|
|
71363
71690
|
</svg>`;
|
|
@@ -71388,49 +71715,34 @@ const sampleNameImageHover =
|
|
|
71388
71715
|
* THE SOFTWARE.
|
|
71389
71716
|
*/
|
|
71390
71717
|
|
|
71391
|
-
class
|
|
71718
|
+
class ROITableControl extends NavbarButton {
|
|
71392
71719
|
|
|
71393
|
-
constructor(parent, browser)
|
|
71720
|
+
constructor(parent, browser) {
|
|
71394
71721
|
|
|
71395
|
-
super(browser,
|
|
71722
|
+
super(parent, browser, ['ROI', 'Regions of Interest Table'], buttonLabel, roiImage, roiImageHover, false);
|
|
71396
71723
|
|
|
71397
71724
|
this.button.addEventListener('mouseenter', () => {
|
|
71398
|
-
if (false === browser.
|
|
71725
|
+
if (false === browser.doShowROITable) {
|
|
71399
71726
|
this.setState(true);
|
|
71400
71727
|
}
|
|
71401
71728
|
});
|
|
71402
71729
|
|
|
71403
71730
|
this.button.addEventListener('mouseleave', () => {
|
|
71404
|
-
if (false === browser.
|
|
71731
|
+
if (false === browser.doShowROITable) {
|
|
71405
71732
|
this.setState(false);
|
|
71406
71733
|
}
|
|
71407
71734
|
});
|
|
71408
71735
|
|
|
71409
|
-
this.button.addEventListener('click', () =>
|
|
71410
|
-
this.performClickWithState(browser, undefined);
|
|
71411
|
-
});
|
|
71736
|
+
this.button.addEventListener('click', () => this.buttonHandler(!browser.doShowROITable));
|
|
71412
71737
|
|
|
71413
|
-
if
|
|
71414
|
-
this.show();
|
|
71415
|
-
} else {
|
|
71416
|
-
this.hide();
|
|
71417
|
-
}
|
|
71738
|
+
this.setVisibility(false); // Hide initially, it will be un-hidden if ROIs are loaded
|
|
71418
71739
|
|
|
71419
71740
|
}
|
|
71420
71741
|
|
|
71421
|
-
|
|
71422
|
-
|
|
71423
|
-
|
|
71424
|
-
|
|
71425
|
-
const column = browser.columnContainer.querySelector('.igv-sample-name-column');
|
|
71426
|
-
column.style.display = false === browser.showSampleNames ? 'none' : 'flex';
|
|
71427
|
-
|
|
71428
|
-
this.setState(browser.showSampleNames);
|
|
71429
|
-
|
|
71430
|
-
browser.layoutChange();
|
|
71431
|
-
|
|
71742
|
+
buttonHandler(status) {
|
|
71743
|
+
this.setState(status);
|
|
71744
|
+
this.browser.setROITableVisibility(status);
|
|
71432
71745
|
}
|
|
71433
|
-
|
|
71434
71746
|
}
|
|
71435
71747
|
|
|
71436
71748
|
const sampleInfoImage =
|
|
@@ -71534,7 +71846,7 @@ class SampleInfoControl extends NavbarButton {
|
|
|
71534
71846
|
|
|
71535
71847
|
constructor(parent, browser) {
|
|
71536
71848
|
|
|
71537
|
-
super(
|
|
71849
|
+
super(parent, browser, 'Sample Info', buttonLabel, sampleInfoImage, sampleInfoImageHover, false);
|
|
71538
71850
|
|
|
71539
71851
|
this.showSampleInfo = false;
|
|
71540
71852
|
|
|
@@ -71584,141 +71896,102 @@ class SampleInfoControl extends NavbarButton {
|
|
|
71584
71896
|
|
|
71585
71897
|
}
|
|
71586
71898
|
|
|
71587
|
-
const
|
|
71588
|
-
|
|
71589
|
-
|
|
71590
|
-
|
|
71591
|
-
|
|
71592
|
-
|
|
71593
|
-
|
|
71594
|
-
|
|
71595
|
-
|
|
71596
|
-
|
|
71597
|
-
|
|
71598
|
-
|
|
71599
|
-
this.zoomOutButton = div();
|
|
71600
|
-
this.zoomContainer.appendChild(this.zoomOutButton);
|
|
71601
|
-
this.zoomOutButton.appendChild(createIcon('minus-circle'));
|
|
71602
|
-
this.zoomOutButton.addEventListener('click', () => {
|
|
71603
|
-
// browser.zoomWithScaleFactor(2.0)
|
|
71604
|
-
browser.zoomOut();
|
|
71605
|
-
});
|
|
71606
|
-
|
|
71607
|
-
// Range slider
|
|
71608
|
-
const el = div();
|
|
71609
|
-
this.zoomContainer.appendChild(el);
|
|
71610
|
-
this.slider = document.createElement('input');
|
|
71611
|
-
this.slider.type = 'range';
|
|
71612
|
-
|
|
71613
|
-
this.slider.min = `${sliderMin}`;
|
|
71614
|
-
this.slider.max = `${sliderMax}`;
|
|
71615
|
-
|
|
71616
|
-
el.appendChild(this.slider);
|
|
71617
|
-
|
|
71618
|
-
this.slider.addEventListener('change', e => {
|
|
71619
|
-
|
|
71620
|
-
e.preventDefault();
|
|
71621
|
-
e.stopPropagation();
|
|
71622
|
-
|
|
71623
|
-
const referenceFrame = browser.referenceFrameList[0];
|
|
71624
|
-
const {bpLength} = referenceFrame.genome.getChromosome(referenceFrame.chr);
|
|
71625
|
-
const {end, start} = referenceFrame;
|
|
71899
|
+
const sampleNameImage =
|
|
71900
|
+
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71901
|
+
<title>sample names</title>
|
|
71902
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71903
|
+
<g id="sample-names" stroke="#737373">
|
|
71904
|
+
<rect id="Rectangle-Copy-13" stroke-width="12" fill="#FFFFFF" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71905
|
+
<line x1="80" y1="465" x2="541" y2="464.5" id="Line-3-Copy-3" stroke-width="32"></line>
|
|
71906
|
+
<line x1="80" y1="312.5" x2="542" y2="313" id="Line-3" stroke-width="32"></line>
|
|
71907
|
+
<line x1="80" y1="158" x2="541" y2="158" id="Line-3-Copy" stroke-width="32"></line>
|
|
71908
|
+
</g>
|
|
71909
|
+
</g>
|
|
71910
|
+
</svg>`;
|
|
71626
71911
|
|
|
71627
|
-
|
|
71912
|
+
const sampleNameImageHover =
|
|
71913
|
+
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
71914
|
+
<title>sample names hover</title>
|
|
71915
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
71916
|
+
<g id="sample-names-hover">
|
|
71917
|
+
<rect id="Rectangle-Copy-18" stroke="#737373" stroke-width="12" fill="#737373" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
71918
|
+
<line x1="80" y1="465" x2="541" y2="464.5" id="Line-3-Copy-3" stroke="#FFFFFF" stroke-width="32" fill="#FFFFFF"></line>
|
|
71919
|
+
<line x1="80" y1="312.5" x2="542" y2="313" id="Line-3" stroke="#FFFFFF" stroke-width="32" fill="#FFFFFF"></line>
|
|
71920
|
+
<line x1="80" y1="158" x2="541" y2="158" id="Line-3-Copy" stroke="#FFFFFF" stroke-width="32" fill="#FFFFFF"></line>
|
|
71921
|
+
</g>
|
|
71922
|
+
</g>
|
|
71923
|
+
</svg>`;
|
|
71628
71924
|
|
|
71629
|
-
|
|
71630
|
-
|
|
71925
|
+
/*
|
|
71926
|
+
* The MIT License (MIT)
|
|
71927
|
+
*
|
|
71928
|
+
* Copyright (c) 2016 University of California San Diego
|
|
71929
|
+
* Author: Jim Robinson
|
|
71930
|
+
*
|
|
71931
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
71932
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
71933
|
+
* in the Software without restriction, including without limitation the rights
|
|
71934
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
71935
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
71936
|
+
* furnished to do so, subject to the following conditions:
|
|
71937
|
+
*
|
|
71938
|
+
* The above copyright notice and this permission notice shall be included in
|
|
71939
|
+
* all copies or substantial portions of the Software.
|
|
71940
|
+
*
|
|
71941
|
+
*
|
|
71942
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
71943
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
71944
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
71945
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
71946
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
71947
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
71948
|
+
* THE SOFTWARE.
|
|
71949
|
+
*/
|
|
71631
71950
|
|
|
71632
|
-
|
|
71633
|
-
const zoomedExtent = bpLength / scaleFactor;
|
|
71951
|
+
class SampleNameControl extends NavbarButton {
|
|
71634
71952
|
|
|
71635
|
-
|
|
71953
|
+
constructor(parent, browser) {
|
|
71636
71954
|
|
|
71637
|
-
|
|
71955
|
+
super(parent, browser, 'Sample Names', sampleNameButtonLabel, sampleNameImage, sampleNameImageHover, browser.config.showSampleNames);
|
|
71638
71956
|
|
|
71639
|
-
|
|
71957
|
+
this.button.addEventListener('mouseenter', () => {
|
|
71958
|
+
if (false === browser.showSampleNames) {
|
|
71959
|
+
this.setState(true);
|
|
71960
|
+
}
|
|
71961
|
+
});
|
|
71640
71962
|
|
|
71641
|
-
|
|
71642
|
-
|
|
71643
|
-
|
|
71644
|
-
|
|
71645
|
-
|
|
71646
|
-
// browser.zoomWithScaleFactor(0.5)
|
|
71647
|
-
browser.zoomIn();
|
|
71648
|
-
});
|
|
71963
|
+
this.button.addEventListener('mouseleave', () => {
|
|
71964
|
+
if (false === browser.showSampleNames) {
|
|
71965
|
+
this.setState(false);
|
|
71966
|
+
}
|
|
71967
|
+
});
|
|
71649
71968
|
|
|
71650
|
-
|
|
71969
|
+
this.button.addEventListener('click', () => {
|
|
71970
|
+
this.performClickWithState(browser, undefined);
|
|
71971
|
+
});
|
|
71651
71972
|
|
|
71652
|
-
if (
|
|
71653
|
-
this.
|
|
71973
|
+
if (true === browser.config.showSampleNameButton) {
|
|
71974
|
+
this.show();
|
|
71654
71975
|
} else {
|
|
71655
|
-
this.
|
|
71656
|
-
this.update(referenceFrameList);
|
|
71976
|
+
this.hide();
|
|
71657
71977
|
}
|
|
71658
71978
|
|
|
71659
|
-
}
|
|
71660
|
-
|
|
71661
|
-
};
|
|
71662
|
-
|
|
71663
|
-
ZoomWidget.prototype.update = function (referenceFrameList) {
|
|
71664
|
-
|
|
71665
|
-
const referenceFrame = referenceFrameList[0];
|
|
71666
|
-
const {bpLength} = referenceFrame.genome.getChromosome(referenceFrame.chr);
|
|
71667
|
-
const {start, end} = referenceFrame;
|
|
71668
|
-
|
|
71669
|
-
sliderMax = Math.ceil(Math.log2(bpLength / this.browser.minimumBases()));
|
|
71670
|
-
|
|
71671
|
-
this.slider.max = `${sliderMax}`;
|
|
71672
|
-
|
|
71673
|
-
const scaleFactor = bpLength / (end - start);
|
|
71674
|
-
sliderValueRaw = Math.log2(scaleFactor);
|
|
71675
|
-
this.slider.value = `${Math.round(sliderValueRaw)}`;
|
|
71676
|
-
|
|
71677
|
-
// referenceFrame.description('zoom.update')
|
|
71678
|
-
|
|
71679
|
-
// console.log(`${ Date.now() } update - slider ${ this.slider.value } scaleFactor ${ Math.round(scaleFactor) } extent ${ StringUtils.numberFormatter(Math.round(extent)) }`)
|
|
71680
|
-
|
|
71681
|
-
// console.log(`update - sliderMin ${ sliderMin } sliderValue ${ this.slider.value } sliderMax ${ sliderMax } scaleFactor ${ scaleFactor.toFixed(3) } derived-scaleFactor ${ derivedScalefactor.toFixed(3) }`)
|
|
71682
|
-
|
|
71683
|
-
};
|
|
71684
|
-
|
|
71685
|
-
ZoomWidget.prototype.enable = function () {
|
|
71686
|
-
|
|
71687
|
-
// this.zoomInButton.style.color = appleCrayonPalette[ 'steel' ];
|
|
71688
|
-
// this.zoomInButton.style.pointerEvents = 'auto';
|
|
71689
|
-
//
|
|
71690
|
-
// this.zoomOutButton.style.color = appleCrayonPalette[ 'steel' ];
|
|
71691
|
-
// this.zoomOutButton.style.pointerEvents = 'auto';
|
|
71692
|
-
|
|
71693
|
-
this.slider.disabled = false;
|
|
71694
|
-
};
|
|
71979
|
+
}
|
|
71695
71980
|
|
|
71696
|
-
|
|
71981
|
+
performClickWithState(browser, doShowSampleNamesOrUndefined) {
|
|
71697
71982
|
|
|
71698
|
-
|
|
71699
|
-
// this.zoomInButton.style.pointerEvents = 'none';
|
|
71700
|
-
//
|
|
71701
|
-
// this.zoomOutButton.style.color = appleCrayonPalette[ 'silver' ];
|
|
71702
|
-
// this.zoomOutButton.style.pointerEvents = 'none';
|
|
71983
|
+
browser.showSampleNames = undefined === doShowSampleNamesOrUndefined ? !browser.showSampleNames : doShowSampleNamesOrUndefined;
|
|
71703
71984
|
|
|
71704
|
-
|
|
71705
|
-
|
|
71985
|
+
const column = browser.columnContainer.querySelector('.igv-sample-name-column');
|
|
71986
|
+
column.style.display = false === browser.showSampleNames ? 'none' : 'flex';
|
|
71706
71987
|
|
|
71707
|
-
|
|
71708
|
-
this.zoomContainer.style.display = 'none';
|
|
71709
|
-
};
|
|
71988
|
+
this.setState(browser.showSampleNames);
|
|
71710
71989
|
|
|
71711
|
-
|
|
71712
|
-
this.zoomContainer.style.display = 'block';
|
|
71713
|
-
};
|
|
71990
|
+
browser.layoutChange();
|
|
71714
71991
|
|
|
71715
|
-
|
|
71716
|
-
this.slider.style.display = 'none';
|
|
71717
|
-
};
|
|
71992
|
+
}
|
|
71718
71993
|
|
|
71719
|
-
|
|
71720
|
-
this.slider.style.display = 'block';
|
|
71721
|
-
};
|
|
71994
|
+
}
|
|
71722
71995
|
|
|
71723
71996
|
class Dropdown {
|
|
71724
71997
|
constructor(parent, shim) {
|
|
@@ -71861,7 +72134,7 @@ const imageSaveImageHoverSVG =
|
|
|
71861
72134
|
class SaveImageControl extends NavbarButton {
|
|
71862
72135
|
constructor(parent, browser) {
|
|
71863
72136
|
|
|
71864
|
-
super(
|
|
72137
|
+
super(parent, browser, 'Save Image', buttonLabel, imageSaveImageSVG, imageSaveImageHoverSVG, false);
|
|
71865
72138
|
|
|
71866
72139
|
this.button.addEventListener('mouseenter', () => this.setState(true));
|
|
71867
72140
|
|
|
@@ -71927,6 +72200,422 @@ class SaveImageControl extends NavbarButton {
|
|
|
71927
72200
|
|
|
71928
72201
|
}
|
|
71929
72202
|
|
|
72203
|
+
/**
|
|
72204
|
+
* User supplied button for the navbar
|
|
72205
|
+
*/
|
|
72206
|
+
|
|
72207
|
+
const CustomButton = function (parent, browser, b) {
|
|
72208
|
+
|
|
72209
|
+
const button = div({class: 'igv-navbar-button'});
|
|
72210
|
+
parent.append(button);
|
|
72211
|
+
button.textContent = b.label;
|
|
72212
|
+
button.addEventListener('click', () => b.callback(browser));
|
|
72213
|
+
};
|
|
72214
|
+
|
|
72215
|
+
const sliderMin = 0;
|
|
72216
|
+
let sliderMax = 23;
|
|
72217
|
+
let sliderValueRaw = 0;
|
|
72218
|
+
|
|
72219
|
+
class ZoomWidget {
|
|
72220
|
+
constructor(config, browser, parent) {
|
|
72221
|
+
|
|
72222
|
+
this.browser = browser;
|
|
72223
|
+
|
|
72224
|
+
this.zoomContainer = div({class: 'igv-zoom-widget'});
|
|
72225
|
+
parent.appendChild(this.zoomContainer);
|
|
72226
|
+
|
|
72227
|
+
// zoom out
|
|
72228
|
+
this.zoomOutButton = div();
|
|
72229
|
+
this.zoomContainer.appendChild(this.zoomOutButton);
|
|
72230
|
+
this.zoomOutButton.appendChild(createIcon('minus-circle'));
|
|
72231
|
+
this.zoomOutButton.addEventListener('click', () => {
|
|
72232
|
+
// browser.zoomWithScaleFactor(2.0)
|
|
72233
|
+
browser.zoomOut();
|
|
72234
|
+
});
|
|
72235
|
+
|
|
72236
|
+
// Range slider
|
|
72237
|
+
const el = div();
|
|
72238
|
+
this.zoomContainer.appendChild(el);
|
|
72239
|
+
this.slider = document.createElement('input');
|
|
72240
|
+
this.slider.type = 'range';
|
|
72241
|
+
|
|
72242
|
+
this.slider.min = `${sliderMin}`;
|
|
72243
|
+
this.slider.max = `${sliderMax}`;
|
|
72244
|
+
|
|
72245
|
+
el.appendChild(this.slider);
|
|
72246
|
+
|
|
72247
|
+
this.slider.addEventListener('change', e => {
|
|
72248
|
+
|
|
72249
|
+
e.preventDefault();
|
|
72250
|
+
e.stopPropagation();
|
|
72251
|
+
|
|
72252
|
+
const referenceFrame = browser.referenceFrameList[0];
|
|
72253
|
+
const {bpLength} = referenceFrame.genome.getChromosome(referenceFrame.chr);
|
|
72254
|
+
const {end, start} = referenceFrame;
|
|
72255
|
+
|
|
72256
|
+
const extent = end - start;
|
|
72257
|
+
|
|
72258
|
+
// bpLength/(end - start)
|
|
72259
|
+
const scaleFactor = Math.pow(2, e.target.valueAsNumber);
|
|
72260
|
+
|
|
72261
|
+
// (end - start) = bpLength/scaleFactor
|
|
72262
|
+
const zoomedExtent = bpLength / scaleFactor;
|
|
72263
|
+
|
|
72264
|
+
// console.log(`zoom-widget - slider ${ e.target.value } scaleFactor ${ scaleFactor } extent-zoomed ${ StringUtils.numberFormatter(Math.round(zoomedExtent)) }`)
|
|
72265
|
+
|
|
72266
|
+
browser.zoomWithScaleFactor(zoomedExtent / extent);
|
|
72267
|
+
|
|
72268
|
+
});
|
|
72269
|
+
|
|
72270
|
+
// zoom in
|
|
72271
|
+
this.zoomInButton = div();
|
|
72272
|
+
this.zoomContainer.appendChild(this.zoomInButton);
|
|
72273
|
+
this.zoomInButton.appendChild(createIcon('plus-circle'));
|
|
72274
|
+
this.zoomInButton.addEventListener('click', () => {
|
|
72275
|
+
// browser.zoomWithScaleFactor(0.5)
|
|
72276
|
+
browser.zoomIn();
|
|
72277
|
+
});
|
|
72278
|
+
|
|
72279
|
+
browser.on('locuschange', (referenceFrameList) => {
|
|
72280
|
+
|
|
72281
|
+
if (this.browser.isMultiLocusMode()) {
|
|
72282
|
+
this.disable();
|
|
72283
|
+
} else {
|
|
72284
|
+
this.enable();
|
|
72285
|
+
this.update(referenceFrameList);
|
|
72286
|
+
}
|
|
72287
|
+
|
|
72288
|
+
});
|
|
72289
|
+
|
|
72290
|
+
}
|
|
72291
|
+
|
|
72292
|
+
update(referenceFrameList) {
|
|
72293
|
+
|
|
72294
|
+
if (this.slider) {
|
|
72295
|
+
const referenceFrame = referenceFrameList[0];
|
|
72296
|
+
const {bpLength} = referenceFrame.genome.getChromosome(referenceFrame.chr);
|
|
72297
|
+
const {start, end} = referenceFrame;
|
|
72298
|
+
|
|
72299
|
+
sliderMax = Math.ceil(Math.log2(bpLength / this.browser.minimumBases()));
|
|
72300
|
+
this.slider.max = `${sliderMax}`;
|
|
72301
|
+
|
|
72302
|
+
const scaleFactor = bpLength / (end - start);
|
|
72303
|
+
sliderValueRaw = Math.log2(scaleFactor);
|
|
72304
|
+
this.slider.value = `${Math.round(sliderValueRaw)}`;
|
|
72305
|
+
}
|
|
72306
|
+
}
|
|
72307
|
+
|
|
72308
|
+
|
|
72309
|
+
enable() {
|
|
72310
|
+
|
|
72311
|
+
// this.zoomInButton.style.color = appleCrayonPalette[ 'steel' ];
|
|
72312
|
+
// this.zoomInButton.style.pointerEvents = 'auto';
|
|
72313
|
+
//
|
|
72314
|
+
// this.zoomOutButton.style.color = appleCrayonPalette[ 'steel' ];
|
|
72315
|
+
// this.zoomOutButton.style.pointerEvents = 'auto';
|
|
72316
|
+
|
|
72317
|
+
if (this.slider) this.slider.disabled = false;
|
|
72318
|
+
}
|
|
72319
|
+
|
|
72320
|
+
disable() {
|
|
72321
|
+
|
|
72322
|
+
// this.zoomInButton.style.color = appleCrayonPalette[ 'silver' ];
|
|
72323
|
+
// this.zoomInButton.style.pointerEvents = 'none';
|
|
72324
|
+
//
|
|
72325
|
+
// this.zoomOutButton.style.color = appleCrayonPalette[ 'silver' ];
|
|
72326
|
+
// this.zoomOutButton.style.pointerEvents = 'none';
|
|
72327
|
+
|
|
72328
|
+
if (this.slider) this.slider.disabled = true;
|
|
72329
|
+
}
|
|
72330
|
+
|
|
72331
|
+
hide() {
|
|
72332
|
+
this.zoomContainer.style.display = 'none';
|
|
72333
|
+
}
|
|
72334
|
+
|
|
72335
|
+
show() {
|
|
72336
|
+
this.zoomContainer.style.display = 'block';
|
|
72337
|
+
}
|
|
72338
|
+
|
|
72339
|
+
hideSlider() {
|
|
72340
|
+
if (this.slider) this.slider.style.display = 'none';
|
|
72341
|
+
}
|
|
72342
|
+
|
|
72343
|
+
showSlider() {
|
|
72344
|
+
if (this.slider) this.slider.style.display = 'block';
|
|
72345
|
+
}
|
|
72346
|
+
}
|
|
72347
|
+
|
|
72348
|
+
/*
|
|
72349
|
+
* The MIT License (MIT)
|
|
72350
|
+
*
|
|
72351
|
+
* Copyright (c) 2014 Broad Institute
|
|
72352
|
+
*
|
|
72353
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
72354
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
72355
|
+
* in the Software without restriction, including without limitation the rights
|
|
72356
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
72357
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
72358
|
+
* furnished to do so, subject to the following conditions:
|
|
72359
|
+
*
|
|
72360
|
+
* The above copyright notice and this permission notice shall be included in
|
|
72361
|
+
* all copies or substantial portions of the Software.
|
|
72362
|
+
*
|
|
72363
|
+
*
|
|
72364
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
72365
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
72366
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
72367
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
72368
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
72369
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
72370
|
+
* THE SOFTWARE.
|
|
72371
|
+
*/
|
|
72372
|
+
|
|
72373
|
+
class ResponsiveNavbar {
|
|
72374
|
+
constructor(config, browser) {
|
|
72375
|
+
|
|
72376
|
+
this.browser = browser;
|
|
72377
|
+
this.config = config;
|
|
72378
|
+
|
|
72379
|
+
this.currentClass = 'igv-navbar-text-button';
|
|
72380
|
+
|
|
72381
|
+
// DOM element for
|
|
72382
|
+
const $navBar = $$1('<div>', {class: 'igv-navbar'});
|
|
72383
|
+
this.$navigation = $navBar;
|
|
72384
|
+
|
|
72385
|
+
const $navbarLeftContainer = $$1('<div>', {class: 'igv-navbar-left-container'});
|
|
72386
|
+
$navBar.append($navbarLeftContainer);
|
|
72387
|
+
this.navbarLeftContainer = $navbarLeftContainer.get(0);
|
|
72388
|
+
|
|
72389
|
+
// IGV logo
|
|
72390
|
+
const $logo = $$1('<div>', {class: 'igv-logo'});
|
|
72391
|
+
$navbarLeftContainer.append($logo);
|
|
72392
|
+
|
|
72393
|
+
const logoSvg = logo();
|
|
72394
|
+
logoSvg.css("width", "34px");
|
|
72395
|
+
logoSvg.css("height", "32px");
|
|
72396
|
+
$logo.append(logoSvg);
|
|
72397
|
+
|
|
72398
|
+
this.$current_genome = $$1('<div>', {class: 'igv-current-genome'});
|
|
72399
|
+
$navbarLeftContainer.append(this.$current_genome);
|
|
72400
|
+
this.$current_genome.text('');
|
|
72401
|
+
|
|
72402
|
+
const $genomicLocation = $$1('<div>', {class: 'igv-navbar-genomic-location'});
|
|
72403
|
+
$navbarLeftContainer.append($genomicLocation);
|
|
72404
|
+
|
|
72405
|
+
// chromosome select widget
|
|
72406
|
+
this.chromosomeSelectWidget = new ChromosomeSelectWidget(browser, $genomicLocation.get(0));
|
|
72407
|
+
if (config.showChromosomeWidget !== false) {
|
|
72408
|
+
this.chromosomeSelectWidget.show();
|
|
72409
|
+
} else {
|
|
72410
|
+
this.chromosomeSelectWidget.hide();
|
|
72411
|
+
}
|
|
72412
|
+
|
|
72413
|
+
const $locusSizeGroup = $$1('<div>', {class: 'igv-locus-size-group'});
|
|
72414
|
+
$genomicLocation.append($locusSizeGroup);
|
|
72415
|
+
|
|
72416
|
+
const $searchContainer = $$1('<div>', {class: 'igv-search-container'});
|
|
72417
|
+
$locusSizeGroup.append($searchContainer);
|
|
72418
|
+
|
|
72419
|
+
// browser.$searchInput = $('<input type="text" placeholder="Locus Search">');
|
|
72420
|
+
this.$searchInput = $$1('<input>', {class: 'igv-search-input', type: 'text', placeholder: 'Locus Search'});
|
|
72421
|
+
$searchContainer.append(this.$searchInput);
|
|
72422
|
+
// Stop event propagation to prevent feature track keyboard navigation
|
|
72423
|
+
this.$searchInput[0].addEventListener('keyup', (event) => {
|
|
72424
|
+
event.stopImmediatePropagation();
|
|
72425
|
+
});
|
|
72426
|
+
|
|
72427
|
+
this.$searchInput.change(() => browser.doSearch(this.$searchInput.val()));
|
|
72428
|
+
|
|
72429
|
+
const searchIconContainer = div({class: 'igv-search-icon-container'});
|
|
72430
|
+
$searchContainer.append($$1(searchIconContainer));
|
|
72431
|
+
searchIconContainer.appendChild(createIcon("search"));
|
|
72432
|
+
searchIconContainer.addEventListener('click', () => browser.doSearch(this.$searchInput.val()));
|
|
72433
|
+
|
|
72434
|
+
this.windowSizePanel = new WindowSizePanel($locusSizeGroup.get(0), browser);
|
|
72435
|
+
|
|
72436
|
+
const $navbarRightContainer = $$1('<div>', {class: 'igv-navbar-right-container'});
|
|
72437
|
+
$navBar.append($navbarRightContainer);
|
|
72438
|
+
this.navbarRightContainer = $navbarRightContainer.get(0);
|
|
72439
|
+
|
|
72440
|
+
const $toggle_button_container = $$1('<div class="igv-navbar-toggle-button-container">');
|
|
72441
|
+
$navbarRightContainer.append($toggle_button_container);
|
|
72442
|
+
const toggleButtonContainer = $toggle_button_container.get(0);
|
|
72443
|
+
this.toggle_button_container = toggleButtonContainer; // TODO -- for circular view , refactor this
|
|
72444
|
+
|
|
72445
|
+
this.overlayTrackButton = new OverlayTrackButton(toggleButtonContainer, browser);
|
|
72446
|
+
this.overlayTrackButton.setVisibility(false);
|
|
72447
|
+
|
|
72448
|
+
const showMultiSelect = config.showMultiSelectButton !== false;
|
|
72449
|
+
this.multiTrackSelectButton = new MultiTrackSelectButton(toggleButtonContainer, browser, this, showMultiSelect);
|
|
72450
|
+
|
|
72451
|
+
this.cursorGuideButton = new CursorGuideButton(toggleButtonContainer, browser);
|
|
72452
|
+
|
|
72453
|
+
this.centerLineButton = new CenterLineButton(toggleButtonContainer, browser);
|
|
72454
|
+
|
|
72455
|
+
this.trackLabelControl = new TrackLabelControl(toggleButtonContainer, browser);
|
|
72456
|
+
|
|
72457
|
+
// ROI Control
|
|
72458
|
+
this.roiTableControl = new ROITableControl(toggleButtonContainer, browser);
|
|
72459
|
+
|
|
72460
|
+
this.sampleInfoControl = new SampleInfoControl(toggleButtonContainer, browser);
|
|
72461
|
+
|
|
72462
|
+
this.sampleNameControl = new SampleNameControl(toggleButtonContainer, browser);
|
|
72463
|
+
|
|
72464
|
+
if (true === config.showSVGButton) {
|
|
72465
|
+
this.saveImageControl = new SaveImageControl(toggleButtonContainer, browser);
|
|
72466
|
+
}
|
|
72467
|
+
|
|
72468
|
+
if (config.customButtons) {
|
|
72469
|
+
for (let b of config.customButtons) {
|
|
72470
|
+
new CustomButton(toggleButtonContainer, browser, b);
|
|
72471
|
+
}
|
|
72472
|
+
}
|
|
72473
|
+
|
|
72474
|
+
this.zoomWidget = new ZoomWidget(config, browser, $navbarRightContainer.get(0));
|
|
72475
|
+
|
|
72476
|
+
if (false === config.showNavigation) {
|
|
72477
|
+
this.$navigation.hide();
|
|
72478
|
+
}
|
|
72479
|
+
|
|
72480
|
+
|
|
72481
|
+
|
|
72482
|
+
}
|
|
72483
|
+
|
|
72484
|
+
navbarDidResize() {
|
|
72485
|
+
|
|
72486
|
+
|
|
72487
|
+
const navbarWidth = this.$navigation.width();
|
|
72488
|
+
const currentClass = this.currentNavbarButtonClass();
|
|
72489
|
+
if ('igv-navbar-text-button' === currentClass) {
|
|
72490
|
+
this.textButtonContainerWidth = this.navbarRightContainer.getBoundingClientRect().width;
|
|
72491
|
+
}
|
|
72492
|
+
const browser = this.browser;
|
|
72493
|
+
const isWGV =
|
|
72494
|
+
(browser.isMultiLocusWholeGenomeView()) ||
|
|
72495
|
+
(browser.referenceFrameList && GenomeUtils.isWholeGenomeView(browser.referenceFrameList[0].chr));
|
|
72496
|
+
|
|
72497
|
+
isWGV ? this.windowSizePanel.hide() : this.windowSizePanel.show();
|
|
72498
|
+
|
|
72499
|
+
const {
|
|
72500
|
+
x: leftContainerX,
|
|
72501
|
+
width: leftContainerWidth
|
|
72502
|
+
} = this.navbarLeftContainer.getBoundingClientRect();
|
|
72503
|
+
const leftContainerExtent = leftContainerX + leftContainerWidth;
|
|
72504
|
+
const {x: rightContainerX} = this.navbarRightContainer.getBoundingClientRect();
|
|
72505
|
+
|
|
72506
|
+
const delta = rightContainerX - leftContainerExtent;
|
|
72507
|
+
|
|
72508
|
+
let navbarButtonClass;
|
|
72509
|
+
const threshold = 8;
|
|
72510
|
+
if ('igv-navbar-text-button' === currentClass && delta < threshold) {
|
|
72511
|
+
navbarButtonClass = 'igv-navbar-icon-button';
|
|
72512
|
+
} else if (this.textButtonContainerWidth && 'igv-navbar-icon-button' === currentClass) {
|
|
72513
|
+
const length = navbarWidth - leftContainerExtent;
|
|
72514
|
+
if (length - this.textButtonContainerWidth > threshold) {
|
|
72515
|
+
navbarButtonClass = 'igv-navbar-text-button';
|
|
72516
|
+
}
|
|
72517
|
+
}
|
|
72518
|
+
// Update all the buttons (buttons are listeners)
|
|
72519
|
+
if(navbarButtonClass && currentClass !== navbarButtonClass) {
|
|
72520
|
+
this.currentClass = navbarButtonClass;
|
|
72521
|
+
this.browser.fireEvent('navbar-resize', [navbarButtonClass]);
|
|
72522
|
+
}
|
|
72523
|
+
|
|
72524
|
+
let zoomContainerClass;
|
|
72525
|
+
if (isWGV) {
|
|
72526
|
+
zoomContainerClass = 'igv-zoom-widget-hidden';
|
|
72527
|
+
} else {
|
|
72528
|
+
zoomContainerClass = navbarWidth > 860 ? 'igv-zoom-widget' : 'igv-zoom-widget-900';
|
|
72529
|
+
}
|
|
72530
|
+
$$1(this.zoomWidget.zoomContainer).removeClass();
|
|
72531
|
+
$$1(this.zoomWidget.zoomContainer).addClass(zoomContainerClass);
|
|
72532
|
+
}
|
|
72533
|
+
|
|
72534
|
+
|
|
72535
|
+
setCenterLineButtonVisibility(isWholeGenomeView) {
|
|
72536
|
+
if (isWholeGenomeView) {
|
|
72537
|
+
this.centerLineButton.setVisibility(!isWholeGenomeView);
|
|
72538
|
+
} else {
|
|
72539
|
+
this.centerLineButton.setVisibility(this.config.showCenterGuideButton);
|
|
72540
|
+
}
|
|
72541
|
+
}
|
|
72542
|
+
|
|
72543
|
+
setCursorGuideVisibility(doShowCursorGuide) {
|
|
72544
|
+
if (doShowCursorGuide) {
|
|
72545
|
+
this.cursorGuide.show();
|
|
72546
|
+
} else {
|
|
72547
|
+
this.cursorGuide.hide();
|
|
72548
|
+
}
|
|
72549
|
+
}
|
|
72550
|
+
|
|
72551
|
+
updateGenome(genome) {
|
|
72552
|
+
|
|
72553
|
+
let genomeLabel = (genome.id && genome.id.length < 20 ? genome.id : `${genome.id.substring(0, 8)}...${genome.id.substring(genome.id.length - 8)}`);
|
|
72554
|
+
this.$current_genome.text(genomeLabel);
|
|
72555
|
+
this.$current_genome.attr('title', genome.description);
|
|
72556
|
+
|
|
72557
|
+
// chromosome select widget -- Show this IFF its not explicitly hidden AND the genome has pre-loaded chromosomes
|
|
72558
|
+
const showChromosomeWidget =
|
|
72559
|
+
this.config.showChromosomeWidget !== false &&
|
|
72560
|
+
genome.showChromosomeWidget !== false &&
|
|
72561
|
+
genome.chromosomeNames &&
|
|
72562
|
+
genome.chromosomeNames.length > 1;
|
|
72563
|
+
|
|
72564
|
+
if (showChromosomeWidget) {
|
|
72565
|
+
this.chromosomeSelectWidget.update(genome);
|
|
72566
|
+
this.chromosomeSelectWidget.show();
|
|
72567
|
+
} else {
|
|
72568
|
+
this.chromosomeSelectWidget.hide();
|
|
72569
|
+
}
|
|
72570
|
+
}
|
|
72571
|
+
|
|
72572
|
+
updateLocus(loc, chrName) {
|
|
72573
|
+
if(this.$searchInput) {
|
|
72574
|
+
this.$searchInput.val(loc);
|
|
72575
|
+
}
|
|
72576
|
+
if (this.chromosomeSelectWidget) {
|
|
72577
|
+
this.chromosomeSelectWidget.select.value = chrName;
|
|
72578
|
+
}
|
|
72579
|
+
}
|
|
72580
|
+
|
|
72581
|
+
currentNavbarButtonClass() {
|
|
72582
|
+
return this.currentClass
|
|
72583
|
+
//const el = this.$navigation.get(0).querySelector('.igv-navbar-text-button')
|
|
72584
|
+
//return el ? 'igv-navbar-text-button' : 'igv-navbar-icon-button'
|
|
72585
|
+
}
|
|
72586
|
+
|
|
72587
|
+
setEnableTrackSelection(b) {
|
|
72588
|
+
this.multiTrackSelectButton.setMultiTrackSelection(b);
|
|
72589
|
+
}
|
|
72590
|
+
getEnableTrackSelection() {
|
|
72591
|
+
return this.multiTrackSelectButton.enableMultiTrackSelection
|
|
72592
|
+
}
|
|
72593
|
+
|
|
72594
|
+
hide() {
|
|
72595
|
+
this.$navigation.hide();
|
|
72596
|
+
}
|
|
72597
|
+
|
|
72598
|
+
show() {
|
|
72599
|
+
this.$navigation.show();
|
|
72600
|
+
}
|
|
72601
|
+
|
|
72602
|
+
}
|
|
72603
|
+
|
|
72604
|
+
|
|
72605
|
+
function logo() {
|
|
72606
|
+
|
|
72607
|
+
return $$1(
|
|
72608
|
+
'<svg width="690px" height="324px" viewBox="0 0 690 324" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
|
|
72609
|
+
'<title>IGV</title>' +
|
|
72610
|
+
'<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">' +
|
|
72611
|
+
'<g id="IGV" fill="#666666">' +
|
|
72612
|
+
'<polygon id="Path" points="379.54574 8.00169252 455.581247 8.00169252 515.564813 188.87244 532.884012 253.529506 537.108207 253.529506 554.849825 188.87244 614.833392 8.00169252 689.60164 8.00169252 582.729511 320.722144 486.840288 320.722144"></polygon>' +
|
|
72613
|
+
'<path d="M261.482414,323.793286 C207.975678,323.793286 168.339046,310.552102 142.571329,284.069337 C116.803612,257.586572 103.919946,217.158702 103.919946,162.784513 C103.919946,108.410325 117.437235,67.8415913 144.472217,41.0770945 C171.507199,14.3125977 212.903894,0.930550071 268.663545,0.930550071 C283.025879,0.930550071 298.232828,1.84616386 314.284849,3.6774189 C330.33687,5.50867394 344.839793,7.97378798 357.794056,11.072835 L357.794056,68.968378 C339.48912,65.869331 323.578145,63.5450806 310.060654,61.9955571 C296.543163,60.4460336 284.574731,59.6712835 274.154998,59.6712835 C255.850062,59.6712835 240.502308,61.4320792 228.111274,64.9537236 C215.720241,68.4753679 205.793482,74.2507779 198.330701,82.2801269 C190.867919,90.309476 185.587729,100.87425 182.48997,113.974767 C179.392212,127.075284 177.843356,143.345037 177.843356,162.784513 C177.843356,181.942258 179.251407,198.000716 182.067551,210.960367 C184.883695,223.920018 189.671068,234.41436 196.429813,242.443709 C203.188559,250.473058 212.059279,256.178037 223.042241,259.558815 C234.025202,262.939594 247.683295,264.629958 264.01693,264.629958 C268.241146,264.629958 273.098922,264.489094 278.590403,264.207362 C284.081883,263.925631 289.643684,263.50304 295.275972,262.939577 L295.275972,159.826347 L361.595831,159.826347 L361.595831,308.579859 C344.698967,313.087564 327.239137,316.750019 309.215815,319.567334 C291.192494,322.38465 275.281519,323.793286 261.482414,323.793286 L261.482414,323.793286 L261.482414,323.793286 Z" id="Path"></path>;' +
|
|
72614
|
+
'<polygon id="Path" points="0.81355666 5.00169252 73.0472883 5.00169252 73.0472883 317.722144 0.81355666 317.722144"></polygon>' +
|
|
72615
|
+
'</g> </g> </svg>'
|
|
72616
|
+
)
|
|
72617
|
+
}
|
|
72618
|
+
|
|
71930
72619
|
const viewportColumnManager =
|
|
71931
72620
|
{
|
|
71932
72621
|
createColumns: (columnContainer, count) => {
|
|
@@ -72138,18 +72827,6 @@ CircularViewControl.prototype.hide = function () {
|
|
|
72138
72827
|
this.button.style.display = 'none';
|
|
72139
72828
|
};
|
|
72140
72829
|
|
|
72141
|
-
/**
|
|
72142
|
-
* User supplied button for the navbar
|
|
72143
|
-
*/
|
|
72144
|
-
|
|
72145
|
-
const CustomButton = function (parent, browser, b) {
|
|
72146
|
-
|
|
72147
|
-
const button = div({class: 'igv-navbar-button'});
|
|
72148
|
-
parent.append(button);
|
|
72149
|
-
button.textContent = b.label;
|
|
72150
|
-
button.addEventListener('click', () => b.callback(browser));
|
|
72151
|
-
};
|
|
72152
|
-
|
|
72153
72830
|
const maxSequenceSize = 1000000;
|
|
72154
72831
|
const maxBlatSize = 25000;
|
|
72155
72832
|
|
|
@@ -72914,88 +73591,6 @@ class TrackROISet {
|
|
|
72914
73591
|
}
|
|
72915
73592
|
}
|
|
72916
73593
|
|
|
72917
|
-
const roiImage =
|
|
72918
|
-
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
72919
|
-
<title>roi</title>
|
|
72920
|
-
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
72921
|
-
<g id="roi">
|
|
72922
|
-
<rect id="Rectangle-Copy-23" stroke="#737373" stroke-width="12" fill="#FFFFFF" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
72923
|
-
<text id="ROI" font-family="HelveticaNeue-Bold, Helvetica Neue" font-size="258" font-weight="bold" fill="#737373">
|
|
72924
|
-
<tspan x="81.445" y="389">ROI</tspan>
|
|
72925
|
-
</text>
|
|
72926
|
-
</g>
|
|
72927
|
-
</g>
|
|
72928
|
-
</svg>`;
|
|
72929
|
-
|
|
72930
|
-
const roiImageHover =
|
|
72931
|
-
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
72932
|
-
<title>roi hover</title>
|
|
72933
|
-
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
72934
|
-
<g id="roi-hover">
|
|
72935
|
-
<rect id="Rectangle-Copy-24" stroke="#737373" stroke-width="12" fill="#737373" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
72936
|
-
<text id="ROI" font-family="HelveticaNeue-Bold, Helvetica Neue" font-size="258" font-weight="bold" fill="#FFFFFF">
|
|
72937
|
-
<tspan x="81.445" y="389">ROI</tspan>
|
|
72938
|
-
</text>
|
|
72939
|
-
</g>
|
|
72940
|
-
</g>
|
|
72941
|
-
</svg>`;
|
|
72942
|
-
|
|
72943
|
-
/*
|
|
72944
|
-
* The MIT License (MIT)
|
|
72945
|
-
*
|
|
72946
|
-
* Copyright (c) 2016 University of California San Diego
|
|
72947
|
-
* Author: Jim Robinson
|
|
72948
|
-
*
|
|
72949
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
72950
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
72951
|
-
* in the Software without restriction, including without limitation the rights
|
|
72952
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
72953
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
72954
|
-
* furnished to do so, subject to the following conditions:
|
|
72955
|
-
*
|
|
72956
|
-
* The above copyright notice and this permission notice shall be included in
|
|
72957
|
-
* all copies or substantial portions of the Software.
|
|
72958
|
-
*
|
|
72959
|
-
*
|
|
72960
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
72961
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
72962
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
72963
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
72964
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
72965
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
72966
|
-
* THE SOFTWARE.
|
|
72967
|
-
*/
|
|
72968
|
-
|
|
72969
|
-
class ROITableControl extends NavbarButton {
|
|
72970
|
-
|
|
72971
|
-
constructor(parent, browser) {
|
|
72972
|
-
|
|
72973
|
-
super(browser, parent, [ 'ROI', 'Regions of Interest Table' ], buttonLabel, roiImage, roiImageHover, false);
|
|
72974
|
-
|
|
72975
|
-
this.button.addEventListener('mouseenter', () => {
|
|
72976
|
-
if (false === browser.doShowROITable) {
|
|
72977
|
-
this.setState(true);
|
|
72978
|
-
}
|
|
72979
|
-
});
|
|
72980
|
-
|
|
72981
|
-
this.button.addEventListener('mouseleave', () => {
|
|
72982
|
-
if (false === browser.doShowROITable) {
|
|
72983
|
-
this.setState(false);
|
|
72984
|
-
}
|
|
72985
|
-
});
|
|
72986
|
-
|
|
72987
|
-
this.button.addEventListener('click', () => this.buttonHandler(!browser.doShowROITable));
|
|
72988
|
-
|
|
72989
|
-
this.setVisibility(false); // Hide initially, it will be un-hidden if ROIs are loaded
|
|
72990
|
-
|
|
72991
|
-
}
|
|
72992
|
-
|
|
72993
|
-
buttonHandler(status) {
|
|
72994
|
-
this.setState(status);
|
|
72995
|
-
this.browser.setROITableVisibility(status);
|
|
72996
|
-
}
|
|
72997
|
-
}
|
|
72998
|
-
|
|
72999
73594
|
async function translateSession(juiceboxSession) {
|
|
73000
73595
|
|
|
73001
73596
|
const jbBrowser = juiceboxSession.browsers[0];
|
|
@@ -73032,101 +73627,6 @@ async function translateSession(juiceboxSession) {
|
|
|
73032
73627
|
|
|
73033
73628
|
}
|
|
73034
73629
|
|
|
73035
|
-
const multiSelectImage =
|
|
73036
|
-
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
73037
|
-
<title>multi select</title>
|
|
73038
|
-
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
73039
|
-
<g id="multi-select">
|
|
73040
|
-
<rect id="backdrop-copy-3" stroke="#737373" stroke-width="12" fill="#FFFFFF" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
73041
|
-
<g id="row-copy-3" transform="translate(81, 427)" fill="#737373">
|
|
73042
|
-
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
73043
|
-
<rect id="Rectangle-Copy-16" stroke="#737373" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73044
|
-
</g>
|
|
73045
|
-
<g id="row-copy-2" transform="translate(82, 277)">
|
|
73046
|
-
<rect id="Rectangle" fill-opacity="0.33" fill="#CFCECE" x="133" y="0" width="329" height="70"></rect>
|
|
73047
|
-
<rect id="Rectangle-Copy-16" stroke-opacity="0.32659528" stroke="#CFCECE" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73048
|
-
</g>
|
|
73049
|
-
<g id="row-copy" transform="translate(81, 119)" fill="#737373">
|
|
73050
|
-
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
73051
|
-
<rect id="Rectangle-Copy-17" stroke="#737373" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73052
|
-
</g>
|
|
73053
|
-
</g>
|
|
73054
|
-
</g>
|
|
73055
|
-
</svg>`;
|
|
73056
|
-
|
|
73057
|
-
const multiSelectImageHover =
|
|
73058
|
-
`<svg width="625px" height="625px" viewBox="0 0 625 625" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
73059
|
-
<title>multi select hover</title>
|
|
73060
|
-
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
73061
|
-
<g id="multi-select-hover">
|
|
73062
|
-
<rect id="backdrop-copy-4" stroke="#737373" stroke-width="12" fill="#737373" x="6" y="6" width="613" height="613" rx="135"></rect>
|
|
73063
|
-
<g id="row-copy-3" transform="translate(81, 427)" fill="#FFFFFF">
|
|
73064
|
-
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
73065
|
-
<rect id="Rectangle-Copy-16" stroke="#FFFFFF" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73066
|
-
</g>
|
|
73067
|
-
<g id="row-copy-2" transform="translate(82, 277)">
|
|
73068
|
-
<rect id="Rectangle" fill-opacity="0.33" fill="#CFCECE" x="133" y="0" width="329" height="70"></rect>
|
|
73069
|
-
<rect id="Rectangle-Copy-16" stroke-opacity="0.33" stroke="#CFCECE" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73070
|
-
</g>
|
|
73071
|
-
<g id="row-copy" transform="translate(81, 119)" fill="#FFFFFF">
|
|
73072
|
-
<rect id="Rectangle" x="134" y="0" width="329" height="70"></rect>
|
|
73073
|
-
<rect id="Rectangle-Copy-17" stroke="#FFFFFF" stroke-width="12" x="6" y="6" width="58" height="58"></rect>
|
|
73074
|
-
</g>
|
|
73075
|
-
</g>
|
|
73076
|
-
</g>
|
|
73077
|
-
</svg>`;
|
|
73078
|
-
|
|
73079
|
-
class MultiTrackSelectButton extends NavbarButton {
|
|
73080
|
-
|
|
73081
|
-
constructor(browser, parent, enableMultiTrackSelection) {
|
|
73082
|
-
|
|
73083
|
-
super(browser, parent, 'Select Tracks', buttonLabel, multiSelectImage, multiSelectImageHover, enableMultiTrackSelection = false);
|
|
73084
|
-
this.enableMultiTrackSelection = enableMultiTrackSelection;
|
|
73085
|
-
this.button.addEventListener('mouseenter', event => {
|
|
73086
|
-
if (false === enableMultiTrackSelection) {
|
|
73087
|
-
this.setState(true);
|
|
73088
|
-
}
|
|
73089
|
-
});
|
|
73090
|
-
|
|
73091
|
-
this.button.addEventListener('mouseleave', event => {
|
|
73092
|
-
if (false === enableMultiTrackSelection) {
|
|
73093
|
-
this.setState(false);
|
|
73094
|
-
}
|
|
73095
|
-
});
|
|
73096
|
-
|
|
73097
|
-
const mouseClickHandler = () => {
|
|
73098
|
-
this.setMultiTrackSelection(!this.enableMultiTrackSelection);
|
|
73099
|
-
};
|
|
73100
|
-
|
|
73101
|
-
this.boundMouseClickHandler = mouseClickHandler.bind(this);
|
|
73102
|
-
|
|
73103
|
-
this.button.addEventListener('click', this.boundMouseClickHandler);
|
|
73104
|
-
|
|
73105
|
-
this.setVisibility(true);
|
|
73106
|
-
|
|
73107
|
-
}
|
|
73108
|
-
|
|
73109
|
-
setMultiTrackSelection(enableMultiTrackSelection) {
|
|
73110
|
-
this.enableMultiTrackSelection = enableMultiTrackSelection;
|
|
73111
|
-
for (const trackView of this.browser.trackViews) {
|
|
73112
|
-
if (false === multiTrackSelectExclusionTypes.has(trackView.track.type)) {
|
|
73113
|
-
trackView.setTrackSelectionState(trackView.axis, this.enableMultiTrackSelection);
|
|
73114
|
-
|
|
73115
|
-
// If closing the selection boxes set track selected property to false
|
|
73116
|
-
if (!this.enableMultiTrackSelection) {
|
|
73117
|
-
trackView.track.selected = false;
|
|
73118
|
-
}
|
|
73119
|
-
}
|
|
73120
|
-
}
|
|
73121
|
-
this.setState(this.enableMultiTrackSelection);
|
|
73122
|
-
|
|
73123
|
-
// If enableMultiTrackSelection is false hide Overlay button
|
|
73124
|
-
if (false === this.enableMultiTrackSelection) {
|
|
73125
|
-
this.browser.overlayTrackButton.setVisibility(false);
|
|
73126
|
-
}
|
|
73127
|
-
}
|
|
73128
|
-
}
|
|
73129
|
-
|
|
73130
73630
|
/**
|
|
73131
73631
|
* Chromosome alias source backed by a UCSC bigbed file
|
|
73132
73632
|
*
|
|
@@ -73146,6 +73646,13 @@ class ChromAliasBB {
|
|
|
73146
73646
|
this.reader = new BWReader(config, genome);
|
|
73147
73647
|
}
|
|
73148
73648
|
|
|
73649
|
+
async preload(chrNames) {
|
|
73650
|
+
await this.reader.preload();
|
|
73651
|
+
for(let nm of chrNames) {
|
|
73652
|
+
await this.search(nm);
|
|
73653
|
+
}
|
|
73654
|
+
}
|
|
73655
|
+
|
|
73149
73656
|
/**
|
|
73150
73657
|
* Return the cached canonical chromosome name for the alias. If none found return the alias.
|
|
73151
73658
|
*
|
|
@@ -73221,6 +73728,10 @@ class ChromAliasFile {
|
|
|
73221
73728
|
this.genome = genome;
|
|
73222
73729
|
}
|
|
73223
73730
|
|
|
73731
|
+
async preload() {
|
|
73732
|
+
return this.loadAliases();
|
|
73733
|
+
}
|
|
73734
|
+
|
|
73224
73735
|
/**
|
|
73225
73736
|
* Return the canonical chromosome name for the alias. If none found return the alias
|
|
73226
73737
|
*
|
|
@@ -73273,6 +73784,9 @@ class ChromAliasFile {
|
|
|
73273
73784
|
aliasRecord[key] = tokens[i];
|
|
73274
73785
|
this.aliasRecordCache.set(tokens[i], aliasRecord);
|
|
73275
73786
|
}
|
|
73787
|
+
|
|
73788
|
+
this.aliasRecordCache.set(chr.toLowerCase(), aliasRecord);
|
|
73789
|
+
this.aliasRecordCache.set(chr.toUpperCase(), aliasRecord);
|
|
73276
73790
|
}
|
|
73277
73791
|
}
|
|
73278
73792
|
}
|
|
@@ -73444,6 +73958,9 @@ class ChromAliasDefaults {
|
|
|
73444
73958
|
this.update(id, chromosomeNames);
|
|
73445
73959
|
}
|
|
73446
73960
|
|
|
73961
|
+
async preload() {
|
|
73962
|
+
// no-op
|
|
73963
|
+
}
|
|
73447
73964
|
|
|
73448
73965
|
/**
|
|
73449
73966
|
* Return the canonical chromosome name for the alias. If none found return the alias
|
|
@@ -73545,6 +74062,8 @@ class ChromAliasDefaults {
|
|
|
73545
74062
|
} else if (Number.isInteger(Number(name))) {
|
|
73546
74063
|
record["ucsc"] = "chr" + name;
|
|
73547
74064
|
}
|
|
74065
|
+
|
|
74066
|
+
|
|
73548
74067
|
}
|
|
73549
74068
|
}
|
|
73550
74069
|
|
|
@@ -73552,7 +74071,10 @@ class ChromAliasDefaults {
|
|
|
73552
74071
|
for (let a of Object.values(rec)) {
|
|
73553
74072
|
this.aliasRecordCache.set(a, rec);
|
|
73554
74073
|
}
|
|
74074
|
+
this.aliasRecordCache.set(rec.chr.toLowerCase(), rec);
|
|
74075
|
+
this.aliasRecordCache.set(rec.chr.toUpperCase(), rec);
|
|
73555
74076
|
}
|
|
74077
|
+
|
|
73556
74078
|
}
|
|
73557
74079
|
}
|
|
73558
74080
|
|
|
@@ -73620,7 +74142,7 @@ class Genome {
|
|
|
73620
74142
|
|
|
73621
74143
|
if (config.chromAliasBbURL) {
|
|
73622
74144
|
this.chromAlias = new ChromAliasBB(config.chromAliasBbURL, Object.assign({}, config), this);
|
|
73623
|
-
if(!this.chromosomeNames) {
|
|
74145
|
+
if (!this.chromosomeNames) {
|
|
73624
74146
|
this.chromosomeNames = await this.chromAlias.getChromosomeNames();
|
|
73625
74147
|
}
|
|
73626
74148
|
} else if (config.aliasURL) {
|
|
@@ -73631,17 +74153,17 @@ class Genome {
|
|
|
73631
74153
|
|
|
73632
74154
|
if (config.cytobandBbURL) {
|
|
73633
74155
|
this.cytobandSource = new CytobandFileBB(config.cytobandBbURL, Object.assign({}, config), this);
|
|
73634
|
-
if(!this.chromosomeNames) {
|
|
74156
|
+
if (!this.chromosomeNames) {
|
|
73635
74157
|
this.chromosomeNames = await this.cytobandSource.getChromosomeNames();
|
|
73636
74158
|
}
|
|
73637
74159
|
} else if (config.cytobandURL) {
|
|
73638
74160
|
this.cytobandSource = new CytobandFile(config.cytobandURL, Object.assign({}, config));
|
|
73639
|
-
if(!this.chromosomeNames) {
|
|
74161
|
+
if (!this.chromosomeNames) {
|
|
73640
74162
|
this.chromosomeNames = await this.cytobandSource.getChromosomeNames();
|
|
73641
74163
|
}
|
|
73642
|
-
if(this.chromosomes.size === 0) {
|
|
74164
|
+
if (this.chromosomes.size === 0) {
|
|
73643
74165
|
const c = await this.cytobandSource.getChromosomes();
|
|
73644
|
-
for(let chromosome of c) {
|
|
74166
|
+
for (let chromosome of c) {
|
|
73645
74167
|
this.chromosomes.set(c.name, c);
|
|
73646
74168
|
}
|
|
73647
74169
|
}
|
|
@@ -73659,6 +74181,7 @@ class Genome {
|
|
|
73659
74181
|
} else {
|
|
73660
74182
|
this.#wgChromosomeNames = trimSmallChromosomes(this.chromosomes);
|
|
73661
74183
|
}
|
|
74184
|
+
await this.chromAlias.preload(this.#wgChromosomeNames);
|
|
73662
74185
|
}
|
|
73663
74186
|
|
|
73664
74187
|
// Optionally create the psuedo chromosome "all" to support whole genome view
|
|
@@ -73725,15 +74248,15 @@ class Genome {
|
|
|
73725
74248
|
async loadChromosome(chr) {
|
|
73726
74249
|
|
|
73727
74250
|
if (this.chromAlias) {
|
|
73728
|
-
|
|
73729
|
-
if(chromAliasRecord) {
|
|
74251
|
+
const chromAliasRecord = await this.chromAlias.search(chr);
|
|
74252
|
+
if (chromAliasRecord) {
|
|
73730
74253
|
chr = chromAliasRecord.chr;
|
|
73731
74254
|
}
|
|
73732
74255
|
}
|
|
73733
74256
|
|
|
73734
74257
|
if (!this.chromosomes.has(chr)) {
|
|
73735
74258
|
let chromosome;
|
|
73736
|
-
const
|
|
74259
|
+
const sequenceRecord = await this.sequence.getSequenceRecord(chr);
|
|
73737
74260
|
if (sequenceRecord) {
|
|
73738
74261
|
chromosome = new Chromosome(chr, 0, sequenceRecord.bpLength);
|
|
73739
74262
|
}
|
|
@@ -73743,6 +74266,7 @@ class Genome {
|
|
|
73743
74266
|
|
|
73744
74267
|
return this.chromosomes.get(chr)
|
|
73745
74268
|
}
|
|
74269
|
+
|
|
73746
74270
|
async getAliasRecord(chr) {
|
|
73747
74271
|
if (this.chromAlias) {
|
|
73748
74272
|
return this.chromAlias.search(chr)
|
|
@@ -73762,7 +74286,7 @@ class Genome {
|
|
|
73762
74286
|
}
|
|
73763
74287
|
|
|
73764
74288
|
get wgChromosomeNames() {
|
|
73765
|
-
return this.#wgChromosomeNames ?
|
|
74289
|
+
return this.#wgChromosomeNames ? this.#wgChromosomeNames.slice() : undefined
|
|
73766
74290
|
}
|
|
73767
74291
|
|
|
73768
74292
|
get showChromosomeWidget() {
|
|
@@ -73866,7 +74390,7 @@ class Genome {
|
|
|
73866
74390
|
* @param end
|
|
73867
74391
|
*/
|
|
73868
74392
|
getSequenceInterval(chr, start, end) {
|
|
73869
|
-
if(typeof this.sequence.getSequenceInterval === 'function') {
|
|
74393
|
+
if (typeof this.sequence.getSequenceInterval === 'function') {
|
|
73870
74394
|
return this.sequence.getSequenceInterval(chr, start, end)
|
|
73871
74395
|
} else {
|
|
73872
74396
|
return undefined
|
|
@@ -74035,6 +74559,125 @@ brewer.push("rgb(188, 128, 189)");
|
|
|
74035
74559
|
brewer.push("rgb(204, 235, 197)");
|
|
74036
74560
|
brewer.push("rgb(255, 237, 111)");
|
|
74037
74561
|
|
|
74562
|
+
class SliderDialog {
|
|
74563
|
+
|
|
74564
|
+
constructor(parent) {
|
|
74565
|
+
|
|
74566
|
+
this.parent = parent;
|
|
74567
|
+
|
|
74568
|
+
// dialog container
|
|
74569
|
+
this.container = div({class: 'igv-ui-generic-dialog-container'});
|
|
74570
|
+
parent.appendChild(this.container);
|
|
74571
|
+
|
|
74572
|
+
// dialog header
|
|
74573
|
+
const header = div({class: 'igv-ui-generic-dialog-header'});
|
|
74574
|
+
this.container.appendChild(header);
|
|
74575
|
+
|
|
74576
|
+
// dialog label
|
|
74577
|
+
this.label = div({class: 'igv-ui-generic-dialog-one-liner'});
|
|
74578
|
+
this.container.appendChild(this.label);
|
|
74579
|
+
this.label.text = 'Unlabeled';
|
|
74580
|
+
|
|
74581
|
+
// input container
|
|
74582
|
+
this.input_container = div({class: 'igv-ui-generic-dialog-input'});
|
|
74583
|
+
this.container.appendChild(this.input_container);
|
|
74584
|
+
|
|
74585
|
+
// input element
|
|
74586
|
+
let html = `<input type="range" id="igv-slider-dialog-input" name="igv-slider-dialog-input" />`;
|
|
74587
|
+
this._input = document.createRange().createContextualFragment(html).firstChild;
|
|
74588
|
+
this.input_container.appendChild(this._input);
|
|
74589
|
+
|
|
74590
|
+
// output element
|
|
74591
|
+
html = `<output id="igv-slider-dialog-output" name="igv-slider-dialog-output" for="igv-slider-dialog-input"></output>`;
|
|
74592
|
+
this._output = document.createRange().createContextualFragment(html).firstChild;
|
|
74593
|
+
this.input_container.appendChild(this._output);
|
|
74594
|
+
|
|
74595
|
+
|
|
74596
|
+
// ok | cancel
|
|
74597
|
+
const buttons = div({class: 'igv-ui-generic-dialog-ok-cancel'});
|
|
74598
|
+
this.container.appendChild(buttons);
|
|
74599
|
+
|
|
74600
|
+
// ok
|
|
74601
|
+
this.ok = div();
|
|
74602
|
+
buttons.appendChild(this.ok);
|
|
74603
|
+
this.ok.textContent = 'OK';
|
|
74604
|
+
|
|
74605
|
+
// cancel
|
|
74606
|
+
this.cancel = div();
|
|
74607
|
+
buttons.appendChild(this.cancel);
|
|
74608
|
+
this.cancel.textContent = 'Cancel';
|
|
74609
|
+
|
|
74610
|
+
hide(this.container);
|
|
74611
|
+
|
|
74612
|
+
this._input.addEventListener('input', () => {
|
|
74613
|
+
const number = parseFloat(this._input.value)/this._scaleFactor;
|
|
74614
|
+
this.callback(number);
|
|
74615
|
+
this._output.value = `${number.toFixed(2)}`;
|
|
74616
|
+
}, false);
|
|
74617
|
+
|
|
74618
|
+
this.ok.addEventListener('click', () => {
|
|
74619
|
+
if (typeof this.callback === 'function') {
|
|
74620
|
+
const number = parseFloat(this._input.value)/this._scaleFactor;
|
|
74621
|
+
this.callback(number);
|
|
74622
|
+
this.callback = undefined;
|
|
74623
|
+
}
|
|
74624
|
+
this._input.value = undefined;
|
|
74625
|
+
hide(this.container);
|
|
74626
|
+
});
|
|
74627
|
+
|
|
74628
|
+
const cancel = () => {
|
|
74629
|
+
this._input.value = undefined;
|
|
74630
|
+
hide(this.container);
|
|
74631
|
+
};
|
|
74632
|
+
|
|
74633
|
+
this.cancel.addEventListener('click', cancel);
|
|
74634
|
+
|
|
74635
|
+
attachDialogCloseHandlerWithParent(header, cancel);
|
|
74636
|
+
makeDraggable(this.container, header);
|
|
74637
|
+
|
|
74638
|
+
}
|
|
74639
|
+
|
|
74640
|
+
get value() {
|
|
74641
|
+
return purify.sanitize(this._input.value)
|
|
74642
|
+
}
|
|
74643
|
+
|
|
74644
|
+
present(options, e) {
|
|
74645
|
+
|
|
74646
|
+
this.label.textContent = options.label;
|
|
74647
|
+
|
|
74648
|
+
this._scaleFactor = options.scaleFactor;
|
|
74649
|
+
const [ minS, maxS, valueS ] = [ options.min, options.max, options.value ].map(number => (Math.floor(this._scaleFactor * number)).toString());
|
|
74650
|
+
|
|
74651
|
+
this._input.min = minS;
|
|
74652
|
+
this._input.max = maxS;
|
|
74653
|
+
this._input.value = valueS;
|
|
74654
|
+
|
|
74655
|
+
const numer = parseFloat(valueS);
|
|
74656
|
+
const denom = this._scaleFactor;
|
|
74657
|
+
const number = numer/denom;
|
|
74658
|
+
this._output.value = `${number.toFixed(2)}`;
|
|
74659
|
+
|
|
74660
|
+
this.callback = options.callback || options.click;
|
|
74661
|
+
|
|
74662
|
+
show(this.container);
|
|
74663
|
+
this.clampLocation(e.clientX, e.clientY);
|
|
74664
|
+
|
|
74665
|
+
}
|
|
74666
|
+
|
|
74667
|
+
clampLocation(clientX, clientY) {
|
|
74668
|
+
|
|
74669
|
+
const {width: w, height: h} = this.container.getBoundingClientRect();
|
|
74670
|
+
const wh = window.innerHeight;
|
|
74671
|
+
const ww = window.innerWidth;
|
|
74672
|
+
|
|
74673
|
+
const y = Math.min(wh - h, clientY);
|
|
74674
|
+
const x = Math.min(ww - w, clientX);
|
|
74675
|
+
this.container.style.left = `${x}px`;
|
|
74676
|
+
this.container.style.top = `${y}px`;
|
|
74677
|
+
|
|
74678
|
+
}
|
|
74679
|
+
}
|
|
74680
|
+
|
|
74038
74681
|
// css - $igv-scrollbar-outer-width: 14px;
|
|
74039
74682
|
const igv_scrollbar_outer_width = 14;
|
|
74040
74683
|
|
|
@@ -74124,7 +74767,6 @@ class Browser {
|
|
|
74124
74767
|
this.sampleNameControl.setState(this.showSampleNames);
|
|
74125
74768
|
this.sampleNameControl.hide();
|
|
74126
74769
|
|
|
74127
|
-
|
|
74128
74770
|
this.layoutChange();
|
|
74129
74771
|
}
|
|
74130
74772
|
});
|
|
@@ -74143,7 +74785,7 @@ class Browser {
|
|
|
74143
74785
|
|
|
74144
74786
|
this.sampleInfo = new SampleInfo(this);
|
|
74145
74787
|
|
|
74146
|
-
this.
|
|
74788
|
+
this.createStandardControls(config);
|
|
74147
74789
|
|
|
74148
74790
|
// Region of interest
|
|
74149
74791
|
this.roiManager = new ROIManager(this);
|
|
@@ -74201,121 +74843,18 @@ class Browser {
|
|
|
74201
74843
|
}
|
|
74202
74844
|
}
|
|
74203
74845
|
|
|
74204
|
-
setControls(config) {
|
|
74205
|
-
|
|
74206
|
-
const $navBar = this.createStandardControls(config);
|
|
74207
|
-
$navBar.insertBefore($$1(this.columnContainer));
|
|
74208
|
-
this.$navigation = $navBar;
|
|
74209
|
-
|
|
74210
|
-
if (false === config.showControls) {
|
|
74211
|
-
$navBar.hide();
|
|
74212
|
-
}
|
|
74213
|
-
|
|
74214
|
-
}
|
|
74215
|
-
|
|
74216
74846
|
createStandardControls(config) {
|
|
74217
74847
|
|
|
74218
|
-
const $navBar = $$1('<div>', {class: 'igv-navbar'});
|
|
74219
|
-
this.$navigation = $navBar;
|
|
74220
|
-
|
|
74221
|
-
const $navbarLeftContainer = $$1('<div>', {class: 'igv-navbar-left-container'});
|
|
74222
|
-
$navBar.append($navbarLeftContainer);
|
|
74223
|
-
|
|
74224
|
-
// IGV logo
|
|
74225
|
-
const $logo = $$1('<div>', {class: 'igv-logo'});
|
|
74226
|
-
$navbarLeftContainer.append($logo);
|
|
74227
|
-
|
|
74228
|
-
const logoSvg = logo();
|
|
74229
|
-
logoSvg.css("width", "34px");
|
|
74230
|
-
logoSvg.css("height", "32px");
|
|
74231
|
-
$logo.append(logoSvg);
|
|
74232
|
-
|
|
74233
|
-
this.$current_genome = $$1('<div>', {class: 'igv-current-genome'});
|
|
74234
|
-
$navbarLeftContainer.append(this.$current_genome);
|
|
74235
|
-
this.$current_genome.text('');
|
|
74236
|
-
|
|
74237
|
-
const $genomicLocation = $$1('<div>', {class: 'igv-navbar-genomic-location'});
|
|
74238
|
-
$navbarLeftContainer.append($genomicLocation);
|
|
74239
|
-
|
|
74240
|
-
// chromosome select widget
|
|
74241
|
-
this.chromosomeSelectWidget = new ChromosomeSelectWidget(this, $genomicLocation.get(0));
|
|
74242
|
-
if (config.showChromosomeWidget !== false) {
|
|
74243
|
-
this.chromosomeSelectWidget.show();
|
|
74244
|
-
} else {
|
|
74245
|
-
this.chromosomeSelectWidget.hide();
|
|
74246
|
-
}
|
|
74247
|
-
|
|
74248
|
-
const $locusSizeGroup = $$1('<div>', {class: 'igv-locus-size-group'});
|
|
74249
|
-
$genomicLocation.append($locusSizeGroup);
|
|
74250
|
-
|
|
74251
|
-
const $searchContainer = $$1('<div>', {class: 'igv-search-container'});
|
|
74252
|
-
$locusSizeGroup.append($searchContainer);
|
|
74253
|
-
|
|
74254
|
-
// browser.$searchInput = $('<input type="text" placeholder="Locus Search">');
|
|
74255
|
-
this.$searchInput = $$1('<input>', {class: 'igv-search-input', type: 'text', placeholder: 'Locus Search'});
|
|
74256
|
-
$searchContainer.append(this.$searchInput);
|
|
74257
|
-
// Stop event propagation to prevent feature track keyboard navigation
|
|
74258
|
-
this.$searchInput[0].addEventListener('keyup', (event) => {
|
|
74259
|
-
event.stopImmediatePropagation();
|
|
74260
|
-
});
|
|
74261
|
-
|
|
74262
|
-
this.$searchInput.change(() => this.doSearch(this.$searchInput.val()));
|
|
74263
|
-
|
|
74264
|
-
const searchIconContainer = div({class: 'igv-search-icon-container'});
|
|
74265
|
-
$searchContainer.append($$1(searchIconContainer));
|
|
74266
|
-
|
|
74267
|
-
searchIconContainer.appendChild(createIcon("search"));
|
|
74268
|
-
|
|
74269
|
-
searchIconContainer.addEventListener('click', () => this.doSearch(this.$searchInput.val()));
|
|
74270
|
-
|
|
74271
|
-
this.windowSizePanel = new WindowSizePanel($locusSizeGroup.get(0), this);
|
|
74272
|
-
|
|
74273
|
-
const $navbarRightContainer = $$1('<div>', {class: 'igv-navbar-right-container'});
|
|
74274
|
-
$navBar.append($navbarRightContainer);
|
|
74275
|
-
|
|
74276
|
-
const $toggle_button_container = $$1('<div class="igv-navbar-toggle-button-container">');
|
|
74277
|
-
$navbarRightContainer.append($toggle_button_container);
|
|
74278
|
-
this.$toggle_button_container = $toggle_button_container;
|
|
74279
|
-
|
|
74280
|
-
this.overlayTrackButton = new OverlayTrackButton(this, $toggle_button_container.get(0));
|
|
74281
|
-
this.overlayTrackButton.setVisibility(false);
|
|
74282
|
-
|
|
74283
|
-
this.multiTrackSelectButton = new MultiTrackSelectButton(this, $toggle_button_container.get(0));
|
|
74284
|
-
|
|
74285
|
-
this.cursorGuide = new CursorGuide(this.columnContainer, this);
|
|
74286
|
-
|
|
74287
|
-
this.cursorGuideButton = new CursorGuideButton(this, $toggle_button_container.get(0));
|
|
74288
|
-
|
|
74289
|
-
this.centerLineButton = new CenterLineButton(this, $toggle_button_container.get(0));
|
|
74290
|
-
|
|
74291
74848
|
this.setTrackLabelVisibility(config.showTrackLabels);
|
|
74292
|
-
this.trackLabelControl = new TrackLabelControl($toggle_button_container.get(0), this);
|
|
74293
74849
|
|
|
74294
|
-
|
|
74295
|
-
this.roiTableControl = new ROITableControl($toggle_button_container.get(0), this);
|
|
74296
|
-
|
|
74297
|
-
this.sampleInfoControl = new SampleInfoControl($toggle_button_container.get(0), this);
|
|
74850
|
+
this.navbar = new ResponsiveNavbar(config, this);
|
|
74298
74851
|
|
|
74299
|
-
this.
|
|
74300
|
-
|
|
74301
|
-
if (true === config.showSVGButton) {
|
|
74302
|
-
this.saveImageControl = new SaveImageControl($toggle_button_container.get(0), this);
|
|
74303
|
-
}
|
|
74852
|
+
this.navbar.$navigation.insertBefore($$1(this.columnContainer));
|
|
74304
74853
|
|
|
74305
|
-
if (config.
|
|
74306
|
-
|
|
74307
|
-
new CustomButton($toggle_button_container.get(0), this, b);
|
|
74308
|
-
}
|
|
74309
|
-
}
|
|
74310
|
-
|
|
74311
|
-
this.zoomWidget = new ZoomWidget(this, $navbarRightContainer.get(0));
|
|
74312
|
-
|
|
74313
|
-
if (false === config.showNavigation) {
|
|
74314
|
-
this.$navigation.hide();
|
|
74854
|
+
if (false === config.showControls) {
|
|
74855
|
+
this.navbar.hide();
|
|
74315
74856
|
}
|
|
74316
|
-
|
|
74317
|
-
this.sliderDialog = new SliderDialog(this.root);
|
|
74318
|
-
this.sliderDialog.container.id = `igv-slider-dialog-${guid$2()}`;
|
|
74857
|
+
this.cursorGuide = new CursorGuide(this.columnContainer, this);
|
|
74319
74858
|
|
|
74320
74859
|
this.inputDialog = new InputDialog(this.root);
|
|
74321
74860
|
this.inputDialog.container.id = `igv-input-dialog-${guid$2()}`;
|
|
@@ -74326,7 +74865,8 @@ class Browser {
|
|
|
74326
74865
|
this.genericColorPicker = new GenericColorPicker({parent: this.columnContainer, width: 432});
|
|
74327
74866
|
this.genericColorPicker.container.id = `igv-track-color-picker-${guid$2()}`;
|
|
74328
74867
|
|
|
74329
|
-
|
|
74868
|
+
this.sliderDialog = new SliderDialog(this.root);
|
|
74869
|
+
this.sliderDialog.container.id = `igv-slider-dialog-${guid$2()}`;
|
|
74330
74870
|
|
|
74331
74871
|
}
|
|
74332
74872
|
|
|
@@ -74557,10 +75097,10 @@ class Browser {
|
|
|
74557
75097
|
session = await translateSession(session);
|
|
74558
75098
|
}
|
|
74559
75099
|
|
|
74560
|
-
this.sampleInfoControl.setButtonVisibility(false);
|
|
75100
|
+
this.navbar.sampleInfoControl.setButtonVisibility(false);
|
|
74561
75101
|
|
|
74562
75102
|
this.showSampleNames = session.showSampleNames || false;
|
|
74563
|
-
this.sampleNameControl.setState(this.showSampleNames === true);
|
|
75103
|
+
this.navbar.sampleNameControl.setState(this.showSampleNames === true);
|
|
74564
75104
|
|
|
74565
75105
|
if (session.sampleNameViewportWidth) {
|
|
74566
75106
|
this.sampleNameViewportWidth = session.sampleNameViewportWidth;
|
|
@@ -74680,9 +75220,9 @@ class Browser {
|
|
|
74680
75220
|
await rtv.updateViews();
|
|
74681
75221
|
}
|
|
74682
75222
|
|
|
74683
|
-
// If any tracks are selected show the
|
|
75223
|
+
// If any tracks are selected show the selection buttons
|
|
74684
75224
|
if (this.trackViews.some(tv => tv.track.selected)) {
|
|
74685
|
-
this.
|
|
75225
|
+
this.navbar.setEnableTrackSelection(true);
|
|
74686
75226
|
}
|
|
74687
75227
|
|
|
74688
75228
|
this.updateUIWithReferenceFrameList();
|
|
@@ -74723,7 +75263,8 @@ class Browser {
|
|
|
74723
75263
|
|
|
74724
75264
|
this.removeAllTracks(); // Do this first, before new genome is set
|
|
74725
75265
|
this.roiManager.clearROIs();
|
|
74726
|
-
|
|
75266
|
+
|
|
75267
|
+
this.navbar.setEnableTrackSelection(false);
|
|
74727
75268
|
|
|
74728
75269
|
let genome;
|
|
74729
75270
|
if (genomeConfig.gbkURL) {
|
|
@@ -74736,8 +75277,7 @@ class Browser {
|
|
|
74736
75277
|
|
|
74737
75278
|
this.genome = genome;
|
|
74738
75279
|
|
|
74739
|
-
this.
|
|
74740
|
-
|
|
75280
|
+
this.navbar.updateGenome(genome);
|
|
74741
75281
|
|
|
74742
75282
|
let locus = initialLocus || genome.initialLocus;
|
|
74743
75283
|
if (Array.isArray(locus)) {
|
|
@@ -74768,26 +75308,6 @@ class Browser {
|
|
|
74768
75308
|
}
|
|
74769
75309
|
}
|
|
74770
75310
|
|
|
74771
|
-
updateNavbarDOMWithGenome(genome) {
|
|
74772
|
-
let genomeLabel = (genome.id && genome.id.length < 20 ? genome.id : `${genome.id.substring(0, 8)}...${genome.id.substring(genome.id.length - 8)}`);
|
|
74773
|
-
this.$current_genome.text(genomeLabel);
|
|
74774
|
-
this.$current_genome.attr('title', genome.description);
|
|
74775
|
-
|
|
74776
|
-
// chromosome select widget -- Show this IFF its not explicitly hidden AND the genome has pre-loaded chromosomes
|
|
74777
|
-
const showChromosomeWidget =
|
|
74778
|
-
this.config.showChromosomeWidget !== false &&
|
|
74779
|
-
this.genome.showChromosomeWidget !== false &&
|
|
74780
|
-
genome.chromosomeNames &&
|
|
74781
|
-
genome.chromosomeNames.length > 1;
|
|
74782
|
-
|
|
74783
|
-
if (showChromosomeWidget) {
|
|
74784
|
-
this.chromosomeSelectWidget.update(genome);
|
|
74785
|
-
this.chromosomeSelectWidget.show();
|
|
74786
|
-
} else {
|
|
74787
|
-
this.chromosomeSelectWidget.hide();
|
|
74788
|
-
}
|
|
74789
|
-
}
|
|
74790
|
-
|
|
74791
75311
|
/**
|
|
74792
75312
|
* Load a genome, defined by a string ID or a json-like configuration object. This includes a fasta reference
|
|
74793
75313
|
* as well as optional cytoband and annotation tracks.
|
|
@@ -74872,16 +75392,16 @@ class Browser {
|
|
|
74872
75392
|
|
|
74873
75393
|
(this.isMultiLocusWholeGenomeView() || GenomeUtils.isWholeGenomeView(referenceFrameList[0].chr));
|
|
74874
75394
|
|
|
74875
|
-
|
|
75395
|
+
this.navbar.navbarDidResize();
|
|
74876
75396
|
|
|
74877
75397
|
toggleTrackLabels(this.trackViews, this.doShowTrackLabels);
|
|
74878
75398
|
|
|
74879
75399
|
if (this.doShowCenterLine && GenomeUtils.isWholeGenomeView(referenceFrameList[0].chr)) {
|
|
74880
|
-
this.centerLineButton.boundMouseClickHandler();
|
|
75400
|
+
this.navbar.centerLineButton.boundMouseClickHandler();
|
|
74881
75401
|
}
|
|
74882
75402
|
|
|
74883
75403
|
if (this.doShowCursorGuide && GenomeUtils.isWholeGenomeView(referenceFrameList[0].chr)) {
|
|
74884
|
-
this.cursorGuideButton.boundMouseClickHandler();
|
|
75404
|
+
this.navbar.cursorGuideButton.boundMouseClickHandler();
|
|
74885
75405
|
}
|
|
74886
75406
|
|
|
74887
75407
|
this.setCenterLineAndCenterLineButtonVisibility(GenomeUtils.isWholeGenomeView(referenceFrameList[0].chr));
|
|
@@ -74891,9 +75411,9 @@ class Browser {
|
|
|
74891
75411
|
setCenterLineAndCenterLineButtonVisibility(isWholeGenomeView) {
|
|
74892
75412
|
|
|
74893
75413
|
if (isWholeGenomeView) {
|
|
74894
|
-
this.centerLineButton.setVisibility(
|
|
75414
|
+
this.navbar.centerLineButton.setVisibility(false);
|
|
74895
75415
|
} else {
|
|
74896
|
-
this.centerLineButton.setVisibility(this.config.showCenterGuideButton);
|
|
75416
|
+
this.navbar.centerLineButton.setVisibility(this.config.showCenterGuideButton);
|
|
74897
75417
|
}
|
|
74898
75418
|
|
|
74899
75419
|
for (let centerLine of this.centerLineList) {
|
|
@@ -75099,7 +75619,7 @@ class Browser {
|
|
|
75099
75619
|
this.reorderTracks();
|
|
75100
75620
|
this.fireEvent('trackorderchanged', [this.getTrackOrder()]);
|
|
75101
75621
|
|
|
75102
|
-
|
|
75622
|
+
newTrack.trackView.enableTrackSelection(this.navbar.getEnableTrackSelection());
|
|
75103
75623
|
|
|
75104
75624
|
return newTrack
|
|
75105
75625
|
|
|
@@ -75467,8 +75987,7 @@ class Browser {
|
|
|
75467
75987
|
}
|
|
75468
75988
|
|
|
75469
75989
|
if (this.referenceFrameList) {
|
|
75470
|
-
this.
|
|
75471
|
-
navbarDidResize(this, this.$navigation.width());
|
|
75990
|
+
this.navbar.navbarDidResize();
|
|
75472
75991
|
}
|
|
75473
75992
|
|
|
75474
75993
|
resize.call(this);
|
|
@@ -75550,13 +76069,11 @@ class Browser {
|
|
|
75550
76069
|
referenceFrame.end = referenceFrame.start + referenceFrame.bpPerPixel * width;
|
|
75551
76070
|
}
|
|
75552
76071
|
|
|
75553
|
-
|
|
75554
|
-
this.chromosomeSelectWidget.select.value = referenceFrameList.length === 1 ? this.referenceFrameList[0].chr : '';
|
|
75555
|
-
}
|
|
76072
|
+
const chrName = referenceFrameList.length === 1 ? this.referenceFrameList[0].chr : '';
|
|
75556
76073
|
|
|
75557
76074
|
const loc = this.referenceFrameList.map(rf => rf.getLocusString()).join(' ');
|
|
75558
76075
|
|
|
75559
|
-
this
|
|
76076
|
+
this.navbar.updateLocus(loc, chrName);
|
|
75560
76077
|
|
|
75561
76078
|
this.fireEvent('locuschange', [this.referenceFrameList]);
|
|
75562
76079
|
}
|
|
@@ -75831,7 +76348,7 @@ class Browser {
|
|
|
75831
76348
|
async loadSampleInfo(config) {
|
|
75832
76349
|
|
|
75833
76350
|
await this.sampleInfo.loadSampleInfoFile(config.url);
|
|
75834
|
-
|
|
76351
|
+
|
|
75835
76352
|
for (const {sampleInfoViewport} of this.trackViews) {
|
|
75836
76353
|
sampleInfoViewport.setWidth(this.getSampleInfoColumnWidth());
|
|
75837
76354
|
}
|
|
@@ -76287,7 +76804,7 @@ class Browser {
|
|
|
76287
76804
|
createCircularView(container, show) {
|
|
76288
76805
|
show = show === true; // convert undefined to boolean
|
|
76289
76806
|
this.circularView = createCircularView(container, this);
|
|
76290
|
-
this.circularViewControl = new CircularViewControl(this
|
|
76807
|
+
this.circularViewControl = new CircularViewControl(this.navbar.toggle_button_container, this);
|
|
76291
76808
|
this.circularView.setAssembly({
|
|
76292
76809
|
name: this.genome.id,
|
|
76293
76810
|
id: this.genome.id,
|
|
@@ -76307,6 +76824,30 @@ class Browser {
|
|
|
76307
76824
|
this.circularViewControl.setState(isVisible);
|
|
76308
76825
|
}
|
|
76309
76826
|
}
|
|
76827
|
+
|
|
76828
|
+
|
|
76829
|
+
|
|
76830
|
+
// Navbar delegates
|
|
76831
|
+
get sampleInfoControl() {
|
|
76832
|
+
return this.navbar.sampleInfoControl
|
|
76833
|
+
}
|
|
76834
|
+
|
|
76835
|
+
get overlayTrackButton() {
|
|
76836
|
+
return this.navbar.overlayTrackButton
|
|
76837
|
+
}
|
|
76838
|
+
|
|
76839
|
+
get roiTableControl() {
|
|
76840
|
+
return this.navbar.roiTableControl
|
|
76841
|
+
}
|
|
76842
|
+
|
|
76843
|
+
get sampleInfoControl() {
|
|
76844
|
+
return this.navbar.sampleInfoControl
|
|
76845
|
+
}
|
|
76846
|
+
|
|
76847
|
+
get sampleNameControl() {
|
|
76848
|
+
return this.navbar.sampleNameControl
|
|
76849
|
+
}
|
|
76850
|
+
|
|
76310
76851
|
}
|
|
76311
76852
|
|
|
76312
76853
|
function getFileExtension(input) {
|
|
@@ -76516,21 +77057,6 @@ async function keyUpHandler(event) {
|
|
|
76516
77057
|
}
|
|
76517
77058
|
}
|
|
76518
77059
|
|
|
76519
|
-
|
|
76520
|
-
function logo() {
|
|
76521
|
-
|
|
76522
|
-
return $$1(
|
|
76523
|
-
'<svg width="690px" height="324px" viewBox="0 0 690 324" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
|
|
76524
|
-
'<title>IGV</title>' +
|
|
76525
|
-
'<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">' +
|
|
76526
|
-
'<g id="IGV" fill="#666666">' +
|
|
76527
|
-
'<polygon id="Path" points="379.54574 8.00169252 455.581247 8.00169252 515.564813 188.87244 532.884012 253.529506 537.108207 253.529506 554.849825 188.87244 614.833392 8.00169252 689.60164 8.00169252 582.729511 320.722144 486.840288 320.722144"></polygon>' +
|
|
76528
|
-
'<path d="M261.482414,323.793286 C207.975678,323.793286 168.339046,310.552102 142.571329,284.069337 C116.803612,257.586572 103.919946,217.158702 103.919946,162.784513 C103.919946,108.410325 117.437235,67.8415913 144.472217,41.0770945 C171.507199,14.3125977 212.903894,0.930550071 268.663545,0.930550071 C283.025879,0.930550071 298.232828,1.84616386 314.284849,3.6774189 C330.33687,5.50867394 344.839793,7.97378798 357.794056,11.072835 L357.794056,68.968378 C339.48912,65.869331 323.578145,63.5450806 310.060654,61.9955571 C296.543163,60.4460336 284.574731,59.6712835 274.154998,59.6712835 C255.850062,59.6712835 240.502308,61.4320792 228.111274,64.9537236 C215.720241,68.4753679 205.793482,74.2507779 198.330701,82.2801269 C190.867919,90.309476 185.587729,100.87425 182.48997,113.974767 C179.392212,127.075284 177.843356,143.345037 177.843356,162.784513 C177.843356,181.942258 179.251407,198.000716 182.067551,210.960367 C184.883695,223.920018 189.671068,234.41436 196.429813,242.443709 C203.188559,250.473058 212.059279,256.178037 223.042241,259.558815 C234.025202,262.939594 247.683295,264.629958 264.01693,264.629958 C268.241146,264.629958 273.098922,264.489094 278.590403,264.207362 C284.081883,263.925631 289.643684,263.50304 295.275972,262.939577 L295.275972,159.826347 L361.595831,159.826347 L361.595831,308.579859 C344.698967,313.087564 327.239137,316.750019 309.215815,319.567334 C291.192494,322.38465 275.281519,323.793286 261.482414,323.793286 L261.482414,323.793286 L261.482414,323.793286 Z" id="Path"></path>;' +
|
|
76529
|
-
'<polygon id="Path" points="0.81355666 5.00169252 73.0472883 5.00169252 73.0472883 317.722144 0.81355666 317.722144"></polygon>' +
|
|
76530
|
-
'</g> </g> </svg>'
|
|
76531
|
-
)
|
|
76532
|
-
}
|
|
76533
|
-
|
|
76534
77060
|
function toggleTrackLabels(trackViews, isVisible) {
|
|
76535
77061
|
|
|
76536
77062
|
for (let {viewports} of trackViews) {
|
|
@@ -76625,7 +77151,7 @@ async function createBrowser(parentDiv, config) {
|
|
|
76625
77151
|
}
|
|
76626
77152
|
|
|
76627
77153
|
browser.stopSpinner();
|
|
76628
|
-
|
|
77154
|
+
browser.navbar.navbarDidResize();
|
|
76629
77155
|
|
|
76630
77156
|
return browser
|
|
76631
77157
|
|