igv 3.0.2 → 3.0.3
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 +1290 -1280
- package/dist/igv.esm.min.js +10 -10
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +1290 -1280
- 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
|
@@ -30744,260 +30744,660 @@ class BaseFeatureSource {
|
|
|
30744
30744
|
|
|
30745
30745
|
}
|
|
30746
30746
|
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
/**
|
|
30750
|
-
* feature source for "bed like" files (tab or whitespace delimited files with 1 feature per line: bed, gff, vcf, etc)
|
|
30747
|
+
/*
|
|
30748
|
+
* The MIT License (MIT)
|
|
30751
30749
|
*
|
|
30752
|
-
*
|
|
30753
|
-
*
|
|
30750
|
+
* Copyright (c) 2016 University of California San Diego
|
|
30751
|
+
* Author: Jim Robinson
|
|
30752
|
+
*
|
|
30753
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
30754
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
30755
|
+
* in the Software without restriction, including without limitation the rights
|
|
30756
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
30757
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
30758
|
+
* furnished to do so, subject to the following conditions:
|
|
30759
|
+
*
|
|
30760
|
+
* The above copyright notice and this permission notice shall be included in
|
|
30761
|
+
* all copies or substantial portions of the Software.
|
|
30762
|
+
*
|
|
30763
|
+
*
|
|
30764
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30765
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
30766
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30767
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
30768
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30769
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
30770
|
+
* THE SOFTWARE.
|
|
30754
30771
|
*/
|
|
30755
|
-
class TextFeatureSource extends BaseFeatureSource {
|
|
30756
30772
|
|
|
30757
|
-
|
|
30773
|
+
const GZIP_FLAG = 0x1;
|
|
30758
30774
|
|
|
30759
|
-
|
|
30775
|
+
class TDFReader {
|
|
30760
30776
|
|
|
30761
|
-
|
|
30777
|
+
constructor(config, genome) {
|
|
30778
|
+
this.config = config;
|
|
30762
30779
|
this.genome = genome;
|
|
30763
|
-
this.
|
|
30764
|
-
this.
|
|
30765
|
-
this.
|
|
30780
|
+
this.path = config.url;
|
|
30781
|
+
this.groupCache = {};
|
|
30782
|
+
this.datasetCache = {};
|
|
30783
|
+
}
|
|
30766
30784
|
|
|
30767
|
-
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "biggenepred", "bignarrowpeak", "tdf"]);
|
|
30768
30785
|
|
|
30769
|
-
|
|
30770
|
-
|
|
30771
|
-
|
|
30772
|
-
this
|
|
30773
|
-
this.queryable = config.queryable !== false;
|
|
30774
|
-
} else if (config.sourceType === "ga4gh") {
|
|
30775
|
-
throw Error("Unsupported source type 'ga4gh'")
|
|
30776
|
-
} else if ((config.type === "eqtl" || config.type === "qtl") && config.sourceType === "gtex-ws") {
|
|
30777
|
-
this.reader = new GtexReader(config);
|
|
30778
|
-
this.queryable = true;
|
|
30779
|
-
} else if ("htsget" === config.sourceType) {
|
|
30780
|
-
this.reader = new HtsgetVariantReader(config, genome);
|
|
30781
|
-
this.queryable = true;
|
|
30782
|
-
} else if (config.sourceType === 'ucscservice') {
|
|
30783
|
-
this.reader = new UCSCServiceReader(config.source);
|
|
30784
|
-
this.queryable = true;
|
|
30785
|
-
} else if (config.sourceType === 'custom') {
|
|
30786
|
-
this.reader = new CustomServiceReader(config.source);
|
|
30787
|
-
this.queryable = false !== config.source.queryable;
|
|
30788
|
-
} else if ('service' === config.sourceType) {
|
|
30789
|
-
this.reader = new FeatureFileReader(config, genome);
|
|
30790
|
-
this.queryable = true;
|
|
30791
|
-
} else {
|
|
30792
|
-
// File of some type (i.e. not a webservice)
|
|
30793
|
-
this.reader = new FeatureFileReader(config, genome);
|
|
30794
|
-
if (config.queryable !== undefined) {
|
|
30795
|
-
this.queryable = config.queryable;
|
|
30796
|
-
} else if (queryableFormats.has(config.format) || this.reader.indexed) {
|
|
30797
|
-
this.queryable = true;
|
|
30798
|
-
} else ;
|
|
30786
|
+
async readHeader() {
|
|
30787
|
+
|
|
30788
|
+
if (this.magic !== undefined) {
|
|
30789
|
+
return this // Already read
|
|
30799
30790
|
}
|
|
30800
30791
|
|
|
30801
|
-
|
|
30802
|
-
|
|
30792
|
+
let data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {range: {start: 0, size: 64000}}));
|
|
30793
|
+
let binaryParser = new BinaryParser$1(new DataView(data));
|
|
30794
|
+
this.magic = binaryParser.getInt();
|
|
30795
|
+
this.version = binaryParser.getInt();
|
|
30796
|
+
this.indexPos = binaryParser.getLong();
|
|
30797
|
+
this.indexSize = binaryParser.getInt();
|
|
30798
|
+
binaryParser.getInt();
|
|
30799
|
+
|
|
30800
|
+
|
|
30801
|
+
if (this.version >= 2) {
|
|
30802
|
+
let nWindowFunctions = binaryParser.getInt();
|
|
30803
|
+
this.windowFunctions = [];
|
|
30804
|
+
while (nWindowFunctions-- > 0) {
|
|
30805
|
+
this.windowFunctions.push(binaryParser.getString());
|
|
30806
|
+
}
|
|
30807
|
+
}
|
|
30808
|
+
|
|
30809
|
+
this.trackType = binaryParser.getString();
|
|
30810
|
+
this.trackLine = binaryParser.getString();
|
|
30811
|
+
|
|
30812
|
+
let nTracks = binaryParser.getInt();
|
|
30813
|
+
this.trackNames = [];
|
|
30814
|
+
while (nTracks-- > 0) {
|
|
30815
|
+
this.trackNames.push(binaryParser.getString());
|
|
30816
|
+
}
|
|
30817
|
+
this.genomeID = binaryParser.getString();
|
|
30818
|
+
this.flags = binaryParser.getInt();
|
|
30819
|
+
this.compressed = (this.flags & GZIP_FLAG) !== 0;
|
|
30803
30820
|
|
|
30821
|
+
// Now read index
|
|
30822
|
+
data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
30823
|
+
range: {
|
|
30824
|
+
start: this.indexPos,
|
|
30825
|
+
size: this.indexSize
|
|
30826
|
+
}
|
|
30827
|
+
}));
|
|
30828
|
+
binaryParser = new BinaryParser$1(new DataView(data));
|
|
30829
|
+
this.datasetIndex = {};
|
|
30830
|
+
let nEntries = binaryParser.getInt();
|
|
30831
|
+
while (nEntries-- > 0) {
|
|
30832
|
+
const name = binaryParser.getString();
|
|
30833
|
+
const pos = binaryParser.getLong();
|
|
30834
|
+
const size = binaryParser.getInt();
|
|
30835
|
+
this.datasetIndex[name] = {position: pos, size: size};
|
|
30836
|
+
}
|
|
30837
|
+
|
|
30838
|
+
this.groupIndex = {};
|
|
30839
|
+
nEntries = binaryParser.getInt();
|
|
30840
|
+
while (nEntries-- > 0) {
|
|
30841
|
+
const name = binaryParser.getString();
|
|
30842
|
+
const pos = binaryParser.getLong();
|
|
30843
|
+
const size = binaryParser.getInt();
|
|
30844
|
+
this.groupIndex[name] = {position: pos, size: size};
|
|
30845
|
+
}
|
|
30846
|
+
|
|
30847
|
+
return this
|
|
30804
30848
|
}
|
|
30805
30849
|
|
|
30806
|
-
async
|
|
30807
|
-
|
|
30808
|
-
|
|
30850
|
+
async readDataset(chr, windowFunction, zoom) {
|
|
30851
|
+
|
|
30852
|
+
const key = chr + "_" + windowFunction + "_" + zoom;
|
|
30853
|
+
|
|
30854
|
+
if (this.datasetCache[key]) {
|
|
30855
|
+
return this.datasetCache[key]
|
|
30856
|
+
|
|
30857
|
+
} else {
|
|
30858
|
+
await this.readHeader();
|
|
30859
|
+
const wf = (this.version < 2) ? "" : "/" + windowFunction;
|
|
30860
|
+
const zoomString = (chr.toLowerCase() === "all" || zoom === undefined) ? "0" : zoom.toString();
|
|
30861
|
+
|
|
30862
|
+
let dsName;
|
|
30863
|
+
if (windowFunction === "raw") {
|
|
30864
|
+
dsName = "/" + chr + "/raw";
|
|
30865
|
+
} else {
|
|
30866
|
+
dsName = "/" + chr + "/z" + zoomString + wf;
|
|
30867
|
+
}
|
|
30868
|
+
const indexEntry = this.datasetIndex[dsName];
|
|
30869
|
+
|
|
30870
|
+
if (indexEntry === undefined) {
|
|
30871
|
+
return undefined
|
|
30872
|
+
}
|
|
30873
|
+
|
|
30874
|
+
const data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
30875
|
+
range: {
|
|
30876
|
+
start: indexEntry.position,
|
|
30877
|
+
size: indexEntry.size
|
|
30878
|
+
}
|
|
30879
|
+
}));
|
|
30880
|
+
|
|
30881
|
+
if (!data) {
|
|
30882
|
+
return undefined
|
|
30883
|
+
}
|
|
30884
|
+
|
|
30885
|
+
const binaryParser = new BinaryParser$1(new DataView(data));
|
|
30886
|
+
let nAttributes = binaryParser.getInt();
|
|
30887
|
+
const attributes = {};
|
|
30888
|
+
while (nAttributes-- > 0) {
|
|
30889
|
+
attributes[binaryParser.getString()] = binaryParser.getString();
|
|
30890
|
+
}
|
|
30891
|
+
const dataType = binaryParser.getString();
|
|
30892
|
+
const tileWidth = binaryParser.getFloat();
|
|
30893
|
+
let nTiles = binaryParser.getInt();
|
|
30894
|
+
const tiles = [];
|
|
30895
|
+
while (nTiles-- > 0) {
|
|
30896
|
+
tiles.push({position: binaryParser.getLong(), size: binaryParser.getInt()});
|
|
30897
|
+
}
|
|
30898
|
+
|
|
30899
|
+
const dataset = {
|
|
30900
|
+
name: dsName,
|
|
30901
|
+
attributes: attributes,
|
|
30902
|
+
dataType: dataType,
|
|
30903
|
+
tileWidth: tileWidth,
|
|
30904
|
+
tiles: tiles
|
|
30905
|
+
};
|
|
30906
|
+
|
|
30907
|
+
this.datasetCache[key] = dataset;
|
|
30908
|
+
return dataset
|
|
30809
30909
|
}
|
|
30810
30910
|
}
|
|
30811
30911
|
|
|
30812
|
-
async
|
|
30813
|
-
|
|
30814
|
-
|
|
30815
|
-
|
|
30912
|
+
async readRootGroup() {
|
|
30913
|
+
|
|
30914
|
+
const genome = this.genome;
|
|
30915
|
+
const rootGroup = this.groupCache["/"];
|
|
30916
|
+
if (rootGroup) {
|
|
30917
|
+
return rootGroup
|
|
30816
30918
|
} else {
|
|
30817
|
-
|
|
30919
|
+
|
|
30920
|
+
const group = await this.readGroup("/");
|
|
30921
|
+
const names = group["chromosomes"];
|
|
30922
|
+
const maxZoomString = group["maxZoom"];
|
|
30923
|
+
|
|
30924
|
+
// Now parse out interesting attributes.
|
|
30925
|
+
if (maxZoomString) {
|
|
30926
|
+
this.maxZoom = Number(maxZoomString);
|
|
30927
|
+
}
|
|
30928
|
+
|
|
30929
|
+
const totalCountString = group["totalCount"];
|
|
30930
|
+
if (totalCountString) {
|
|
30931
|
+
group.totalCount = Number(totalCountString);
|
|
30932
|
+
}
|
|
30933
|
+
|
|
30934
|
+
// Chromosome names
|
|
30935
|
+
const chrAliasTable = {};
|
|
30936
|
+
if (names) {
|
|
30937
|
+
names.split(",").forEach(function (chr) {
|
|
30938
|
+
const canonicalName = genome.getChromosomeName(chr);
|
|
30939
|
+
chrAliasTable[canonicalName] = chr;
|
|
30940
|
+
});
|
|
30941
|
+
}
|
|
30942
|
+
this.chrAliasTable = chrAliasTable;
|
|
30943
|
+
|
|
30944
|
+
this.groupCache["/"] = group;
|
|
30945
|
+
return group
|
|
30818
30946
|
}
|
|
30819
30947
|
}
|
|
30820
30948
|
|
|
30821
|
-
async
|
|
30822
|
-
if (!this.header) {
|
|
30949
|
+
async readGroup(name) {
|
|
30823
30950
|
|
|
30824
|
-
|
|
30825
|
-
|
|
30826
|
-
|
|
30827
|
-
|
|
30828
|
-
|
|
30829
|
-
|
|
30830
|
-
|
|
30831
|
-
|
|
30832
|
-
|
|
30951
|
+
const group = this.groupCache[name];
|
|
30952
|
+
if (group) {
|
|
30953
|
+
return group
|
|
30954
|
+
} else {
|
|
30955
|
+
|
|
30956
|
+
await this.readHeader();
|
|
30957
|
+
const indexEntry = this.groupIndex[name];
|
|
30958
|
+
if (indexEntry === undefined) {
|
|
30959
|
+
return undefined
|
|
30960
|
+
}
|
|
30961
|
+
|
|
30962
|
+
const data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
30963
|
+
range: {
|
|
30964
|
+
start: indexEntry.position,
|
|
30965
|
+
size: indexEntry.size
|
|
30833
30966
|
}
|
|
30834
|
-
}
|
|
30835
|
-
|
|
30967
|
+
}));
|
|
30968
|
+
|
|
30969
|
+
if (!data) {
|
|
30970
|
+
return undefined
|
|
30836
30971
|
}
|
|
30972
|
+
|
|
30973
|
+
const binaryParser = new BinaryParser$1(new DataView(data));
|
|
30974
|
+
const group = {name: name};
|
|
30975
|
+
let nAttributes = binaryParser.getInt();
|
|
30976
|
+
while (nAttributes-- > 0) {
|
|
30977
|
+
const key = binaryParser.getString();
|
|
30978
|
+
const value = binaryParser.getString();
|
|
30979
|
+
group[key] = value;
|
|
30980
|
+
}
|
|
30981
|
+
this.groupCache[name] = group;
|
|
30982
|
+
return group
|
|
30837
30983
|
}
|
|
30838
|
-
return this.header
|
|
30839
30984
|
}
|
|
30840
30985
|
|
|
30841
|
-
|
|
30842
|
-
* Required function for all data source objects. Fetches features for the
|
|
30843
|
-
* range requested.
|
|
30844
|
-
*
|
|
30845
|
-
* This function is quite complex due to the variety of reader types backing it, some indexed, some queryable,
|
|
30846
|
-
* some not.
|
|
30847
|
-
*
|
|
30848
|
-
* @param chr
|
|
30849
|
-
* @param start
|
|
30850
|
-
* @param end
|
|
30851
|
-
* @param bpPerPixel
|
|
30852
|
-
*/
|
|
30853
|
-
async getFeatures({chr, start, end, bpPerPixel, visibilityWindow}) {
|
|
30986
|
+
async readTiles(tileIndeces, nTracks) {
|
|
30854
30987
|
|
|
30855
|
-
|
|
30988
|
+
tileIndeces.sort(function (a, b) {
|
|
30989
|
+
return a.position - b.position
|
|
30990
|
+
});
|
|
30856
30991
|
|
|
30857
|
-
|
|
30858
|
-
|
|
30992
|
+
tileIndeces = tileIndeces.filter(function (idx) {
|
|
30993
|
+
return idx.size > 0
|
|
30994
|
+
});
|
|
30859
30995
|
|
|
30860
|
-
|
|
30861
|
-
|
|
30862
|
-
// * cache is disabled
|
|
30863
|
-
// * cache does not contain requested range
|
|
30864
|
-
// const containsRange = this.featureCache.containsRange(new GenomicInterval(queryChr, start, end))
|
|
30865
|
-
if ((isWholeGenome && !this.wgFeatures && this.supportsWholeGenome()) ||
|
|
30866
|
-
this.config.disableCache ||
|
|
30867
|
-
!this.featureCache ||
|
|
30868
|
-
!this.featureCache.containsRange(new GenomicInterval(chr, start, end))) {
|
|
30869
|
-
await this.loadFeatures(chr, start, end, visibilityWindow);
|
|
30996
|
+
if (tileIndeces.length === 0) {
|
|
30997
|
+
return []
|
|
30870
30998
|
}
|
|
30871
30999
|
|
|
30872
|
-
|
|
30873
|
-
|
|
30874
|
-
|
|
30875
|
-
|
|
30876
|
-
|
|
30877
|
-
|
|
31000
|
+
const tiles = [];
|
|
31001
|
+
|
|
31002
|
+
for (let indexEntry of tileIndeces) {
|
|
31003
|
+
|
|
31004
|
+
const data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
31005
|
+
range: {
|
|
31006
|
+
start: indexEntry.position,
|
|
31007
|
+
size: indexEntry.size
|
|
30878
31008
|
}
|
|
31009
|
+
}));
|
|
31010
|
+
|
|
31011
|
+
let tileData;
|
|
31012
|
+
try {
|
|
31013
|
+
tileData = this.compressed ? inflate_1$3(data).buffer : data;
|
|
31014
|
+
} catch (e) {
|
|
31015
|
+
console.error(e);
|
|
31016
|
+
continue
|
|
30879
31017
|
}
|
|
30880
|
-
|
|
30881
|
-
|
|
30882
|
-
|
|
31018
|
+
|
|
31019
|
+
const binaryParser = new BinaryParser$1(new DataView(tileData));
|
|
31020
|
+
const type = binaryParser.getString();
|
|
31021
|
+
let tile;
|
|
31022
|
+
switch (type) {
|
|
31023
|
+
case "fixedStep":
|
|
31024
|
+
tile = createFixedStep(binaryParser, nTracks);
|
|
31025
|
+
break
|
|
31026
|
+
case "variableStep":
|
|
31027
|
+
tile = createVariableStep(binaryParser, nTracks);
|
|
31028
|
+
break
|
|
31029
|
+
case "bed":
|
|
31030
|
+
case "bedWithName":
|
|
31031
|
+
tile = createBed(binaryParser, nTracks, type);
|
|
31032
|
+
break
|
|
31033
|
+
default:
|
|
31034
|
+
throw "Unknown tile type: " + type
|
|
31035
|
+
}
|
|
31036
|
+
tiles.push(tile);
|
|
30883
31037
|
}
|
|
31038
|
+
return tiles
|
|
30884
31039
|
}
|
|
30885
31040
|
|
|
30886
|
-
async
|
|
30887
|
-
return this.featureCache ? this.featureCache.findFeatures(fn) : []
|
|
30888
|
-
}
|
|
31041
|
+
async readTile(indexEntry, nTracks) {
|
|
30889
31042
|
|
|
30890
|
-
|
|
30891
|
-
|
|
31043
|
+
let data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
31044
|
+
range: {
|
|
31045
|
+
start: indexEntry.position,
|
|
31046
|
+
size: indexEntry.size
|
|
31047
|
+
}
|
|
31048
|
+
}));
|
|
31049
|
+
|
|
31050
|
+
if (this.compressed) {
|
|
31051
|
+
const plain = inflate_1$3(data);
|
|
31052
|
+
data = plain.buffer;
|
|
31053
|
+
}
|
|
31054
|
+
|
|
31055
|
+
const binaryParser = new BinaryParser$1(new DataView(data));
|
|
31056
|
+
const type = binaryParser.getString();
|
|
31057
|
+
switch (type) {
|
|
31058
|
+
case "fixedStep":
|
|
31059
|
+
return createFixedStep(binaryParser, nTracks)
|
|
31060
|
+
case "variableStep":
|
|
31061
|
+
return createVariableStep(binaryParser, nTracks)
|
|
31062
|
+
case "bed":
|
|
31063
|
+
case "bedWithName":
|
|
31064
|
+
return createBed(binaryParser, nTracks, type)
|
|
31065
|
+
default:
|
|
31066
|
+
throw "Unknown tile type: " + type
|
|
31067
|
+
}
|
|
30892
31068
|
}
|
|
30893
31069
|
|
|
30894
|
-
|
|
30895
|
-
|
|
30896
|
-
|
|
30897
|
-
|
|
30898
|
-
|
|
30899
|
-
|
|
31070
|
+
}
|
|
31071
|
+
|
|
31072
|
+
function createFixedStep(binaryParser, nTracks) {
|
|
31073
|
+
const nPositions = binaryParser.getInt();
|
|
31074
|
+
const start = binaryParser.getInt();
|
|
31075
|
+
const span = binaryParser.getFloat();
|
|
31076
|
+
|
|
31077
|
+
const data = [];
|
|
31078
|
+
let nt = nTracks;
|
|
31079
|
+
while (nt-- > 0) {
|
|
31080
|
+
let np = nPositions;
|
|
31081
|
+
const dtrack = [];
|
|
31082
|
+
while (np-- > 0) {
|
|
31083
|
+
dtrack.push(binaryParser.getFloat());
|
|
30900
31084
|
}
|
|
31085
|
+
data.push(dtrack);
|
|
30901
31086
|
}
|
|
30902
31087
|
|
|
31088
|
+
return {
|
|
31089
|
+
type: "fixedStep",
|
|
31090
|
+
start: start,
|
|
31091
|
+
span: span,
|
|
31092
|
+
data: data,
|
|
31093
|
+
nTracks: nTracks,
|
|
31094
|
+
nPositions: nPositions
|
|
31095
|
+
}
|
|
31096
|
+
}
|
|
30903
31097
|
|
|
30904
|
-
|
|
31098
|
+
function createVariableStep(binaryParser, nTracks) {
|
|
30905
31099
|
|
|
30906
|
-
|
|
31100
|
+
const tileStart = binaryParser.getInt();
|
|
31101
|
+
const span = binaryParser.getFloat();
|
|
31102
|
+
const nPositions = binaryParser.getInt();
|
|
31103
|
+
const start = [];
|
|
30907
31104
|
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
31105
|
+
let np = nPositions;
|
|
31106
|
+
while (np-- > 0) {
|
|
31107
|
+
start.push(binaryParser.getInt());
|
|
31108
|
+
}
|
|
31109
|
+
binaryParser.getInt(); // # of samples, ignored but should === nTracks
|
|
30911
31110
|
|
|
30912
|
-
|
|
30913
|
-
|
|
30914
|
-
|
|
30915
|
-
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
|
|
31111
|
+
const data = [];
|
|
31112
|
+
let nt = nTracks;
|
|
31113
|
+
while (nt-- > 0) {
|
|
31114
|
+
np = nPositions;
|
|
31115
|
+
const dtrack = [];
|
|
31116
|
+
while (np-- > 0) {
|
|
31117
|
+
dtrack.push(binaryParser.getFloat());
|
|
30919
31118
|
}
|
|
31119
|
+
data.push(dtrack);
|
|
31120
|
+
}
|
|
30920
31121
|
|
|
30921
|
-
|
|
30922
|
-
|
|
30923
|
-
|
|
30924
|
-
|
|
30925
|
-
|
|
30926
|
-
|
|
30927
|
-
|
|
30928
|
-
|
|
30929
|
-
|
|
30930
|
-
|
|
30931
|
-
|
|
30932
|
-
|
|
30933
|
-
|
|
30934
|
-
|
|
30935
|
-
|
|
31122
|
+
return {
|
|
31123
|
+
type: "variableStep",
|
|
31124
|
+
tileStart: tileStart,
|
|
31125
|
+
span: span,
|
|
31126
|
+
start: start,
|
|
31127
|
+
data: data,
|
|
31128
|
+
nTracks: nTracks,
|
|
31129
|
+
nPositions: nPositions
|
|
31130
|
+
}
|
|
31131
|
+
}
|
|
31132
|
+
|
|
31133
|
+
function createBed(binaryParser, nTracks, type) {
|
|
31134
|
+
|
|
31135
|
+
const nPositions = binaryParser.getInt();
|
|
31136
|
+
|
|
31137
|
+
let n = nPositions;
|
|
31138
|
+
const start = [];
|
|
31139
|
+
while (n-- > 0) {
|
|
31140
|
+
start.push(binaryParser.getInt());
|
|
31141
|
+
}
|
|
31142
|
+
|
|
31143
|
+
n = nPositions;
|
|
31144
|
+
const end = [];
|
|
31145
|
+
while (n-- > 0) {
|
|
31146
|
+
end.push(binaryParser.getInt());
|
|
31147
|
+
}
|
|
31148
|
+
|
|
31149
|
+
binaryParser.getInt(); // # of samples, ignored but should === nTracks
|
|
31150
|
+
const data = [];
|
|
31151
|
+
let nt = nTracks;
|
|
31152
|
+
while (nt-- > 0) {
|
|
31153
|
+
let np = nPositions;
|
|
31154
|
+
const dtrack = [];
|
|
31155
|
+
while (np-- > 0) {
|
|
31156
|
+
dtrack.push(binaryParser.getFloat());
|
|
30936
31157
|
}
|
|
31158
|
+
data.push(dtrack);
|
|
31159
|
+
}
|
|
30937
31160
|
|
|
30938
|
-
|
|
30939
|
-
|
|
30940
|
-
|
|
31161
|
+
if (type === "bedWithName") {
|
|
31162
|
+
n = nPositions;
|
|
31163
|
+
const name = [];
|
|
31164
|
+
while (n-- > 0) {
|
|
31165
|
+
name.push(binaryParser.getString());
|
|
30941
31166
|
}
|
|
31167
|
+
}
|
|
30942
31168
|
|
|
30943
|
-
|
|
30944
|
-
|
|
30945
|
-
|
|
31169
|
+
return {
|
|
31170
|
+
type: type,
|
|
31171
|
+
start: start,
|
|
31172
|
+
end: end,
|
|
31173
|
+
data: data,
|
|
31174
|
+
nTracks: nTracks,
|
|
31175
|
+
nPositions: nPositions
|
|
31176
|
+
}
|
|
31177
|
+
}
|
|
30946
31178
|
|
|
30947
|
-
|
|
31179
|
+
/*
|
|
31180
|
+
* The MIT License (MIT)
|
|
31181
|
+
*
|
|
31182
|
+
* Copyright (c) 2016 University of California San Diego
|
|
31183
|
+
* Author: Jim Robinson
|
|
31184
|
+
*
|
|
31185
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
31186
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
31187
|
+
* in the Software without restriction, including without limitation the rights
|
|
31188
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
31189
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
31190
|
+
* furnished to do so, subject to the following conditions:
|
|
31191
|
+
*
|
|
31192
|
+
* The above copyright notice and this permission notice shall be included in
|
|
31193
|
+
* all copies or substantial portions of the Software.
|
|
31194
|
+
*
|
|
31195
|
+
*
|
|
31196
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
31197
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31198
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
31199
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31200
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
31201
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
31202
|
+
* THE SOFTWARE.
|
|
31203
|
+
*/
|
|
30948
31204
|
|
|
30949
|
-
|
|
30950
|
-
if (this.config.format !== "wig" && this.config.type !== "junctions") {
|
|
30951
|
-
const maxRows = this.config.maxRows || Number.MAX_SAFE_INTEGER;
|
|
30952
|
-
packFeatures(features, maxRows);
|
|
30953
|
-
}
|
|
31205
|
+
class TDFSource extends BaseFeatureSource {
|
|
30954
31206
|
|
|
30955
|
-
|
|
30956
|
-
|
|
31207
|
+
#wgValues = {}
|
|
31208
|
+
searchable = false
|
|
30957
31209
|
|
|
30958
|
-
|
|
30959
|
-
|
|
30960
|
-
|
|
30961
|
-
|
|
31210
|
+
|
|
31211
|
+
constructor(config, genome) {
|
|
31212
|
+
super(genome);
|
|
31213
|
+
this.genome = genome;
|
|
31214
|
+
this.reader = new TDFReader(config, genome);
|
|
31215
|
+
this.queryable = true;
|
|
31216
|
+
}
|
|
31217
|
+
|
|
31218
|
+
async getFeatures({chr, start, end, bpPerPixel, windowFunction = "mean"}) {
|
|
31219
|
+
|
|
31220
|
+
if (chr.toLowerCase() === "all") {
|
|
31221
|
+
return this.getWGValues(windowFunction, bpPerPixel)
|
|
30962
31222
|
} else {
|
|
30963
|
-
this.
|
|
31223
|
+
return this._getFeatures(chr, start, end, bpPerPixel, windowFunction)
|
|
30964
31224
|
}
|
|
30965
31225
|
}
|
|
31226
|
+
async _getFeatures(chr, start, end, bpPerPixel, windowFunction) {
|
|
31227
|
+
const genomicInterval = new GenomicInterval(chr, start, end);
|
|
31228
|
+
const genome = this.genome;
|
|
30966
31229
|
|
|
30967
|
-
|
|
30968
|
-
if (!this.
|
|
30969
|
-
this.
|
|
30970
|
-
|
|
30971
|
-
|
|
30972
|
-
|
|
30973
|
-
|
|
30974
|
-
let key;
|
|
30975
|
-
if (typeof feature.getAttributeValue === 'function') {
|
|
30976
|
-
key = feature.getAttributeValue(field);
|
|
31230
|
+
|
|
31231
|
+
if (!this.rootGroup) {
|
|
31232
|
+
this.rootGroup = await this.reader.readRootGroup();
|
|
31233
|
+
if (!this.normalizationFactor) {
|
|
31234
|
+
const totalCount = this.rootGroup.totalCount;
|
|
31235
|
+
if (totalCount) {
|
|
31236
|
+
this.normalizationFactor = 1.0e6 / totalCount;
|
|
30977
31237
|
}
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
|
|
30982
|
-
|
|
30983
|
-
|
|
30984
|
-
|
|
31238
|
+
}
|
|
31239
|
+
}
|
|
31240
|
+
|
|
31241
|
+
genomicInterval.bpPerPixel = bpPerPixel;
|
|
31242
|
+
const zoom = zoomLevelForScale$1(chr, bpPerPixel, genome);
|
|
31243
|
+
let queryChr = this.reader.chrAliasTable[chr];
|
|
31244
|
+
let maxZoom = this.reader.maxZoom;
|
|
31245
|
+
if (queryChr === undefined) queryChr = chr;
|
|
31246
|
+
if (maxZoom === undefined) maxZoom = -1;
|
|
31247
|
+
|
|
31248
|
+
const wf = zoom > maxZoom ? "raw" : windowFunction;
|
|
31249
|
+
const dataset = await this.reader.readDataset(queryChr, wf, zoom);
|
|
31250
|
+
if (dataset == null) {
|
|
31251
|
+
return []
|
|
31252
|
+
}
|
|
31253
|
+
|
|
31254
|
+
const tileWidth = dataset.tileWidth;
|
|
31255
|
+
const startTile = Math.floor(start / tileWidth);
|
|
31256
|
+
const endTile = Math.floor(end / tileWidth);
|
|
31257
|
+
const NTRACKS = 1; // TODO read this
|
|
31258
|
+
const tiles = await this.reader.readTiles(dataset.tiles.slice(startTile, endTile + 1), NTRACKS);
|
|
31259
|
+
const features = [];
|
|
31260
|
+
for (let tile of tiles) {
|
|
31261
|
+
switch (tile.type) {
|
|
31262
|
+
case "bed":
|
|
31263
|
+
decodeBedTile(tile, chr, start, end, bpPerPixel, features);
|
|
31264
|
+
break
|
|
31265
|
+
case "variableStep":
|
|
31266
|
+
decodeVaryTile(tile, chr, start, end, bpPerPixel, features);
|
|
31267
|
+
break
|
|
31268
|
+
case "fixedStep":
|
|
31269
|
+
decodeFixedTile(tile, chr, start, end, bpPerPixel, features);
|
|
31270
|
+
break
|
|
31271
|
+
default:
|
|
31272
|
+
throw ("Unknown tile type: " + tile.type)
|
|
31273
|
+
}
|
|
31274
|
+
}
|
|
31275
|
+
features.sort(function (a, b) {
|
|
31276
|
+
return a.start - b.start
|
|
31277
|
+
});
|
|
31278
|
+
|
|
31279
|
+
return features
|
|
31280
|
+
}
|
|
31281
|
+
|
|
31282
|
+
get supportsWholeGenome() {
|
|
31283
|
+
return true
|
|
31284
|
+
}
|
|
31285
|
+
|
|
31286
|
+
get windowFunctions() {
|
|
31287
|
+
return this.reader.windowFunctions
|
|
31288
|
+
}
|
|
31289
|
+
|
|
31290
|
+
async getWGValues(windowFunction, bpPerPixel) {
|
|
31291
|
+
|
|
31292
|
+
const cached = this.#wgValues[windowFunction];
|
|
31293
|
+
if (cached && cached.bpPerPixel > 0.8 * bpPerPixel && cached.bpPerPixel < 1.2 * bpPerPixel) {
|
|
31294
|
+
return cached.values
|
|
31295
|
+
} else {
|
|
31296
|
+
const wgFeatures = [];
|
|
31297
|
+
const genome = this.genome;
|
|
31298
|
+
const chrNames = this.genome.wgChromosomeNames;
|
|
31299
|
+
if (chrNames) {
|
|
31300
|
+
for (let c of genome.wgChromosomeNames) {
|
|
31301
|
+
const len = genome.getChromosome(c).bpLength;
|
|
31302
|
+
bpPerPixel = len / 1000;
|
|
31303
|
+
const chrFeatures = await this._getFeatures(c, 0, len, bpPerPixel, windowFunction);
|
|
31304
|
+
if (chrFeatures) {
|
|
31305
|
+
for (let f of chrFeatures) {
|
|
31306
|
+
const wg = Object.assign({}, f);
|
|
31307
|
+
wg.chr = "all";
|
|
31308
|
+
wg.start = genome.getGenomeCoordinate(f.chr, f.start);
|
|
31309
|
+
wg.end = genome.getGenomeCoordinate(f.chr, f.end);
|
|
31310
|
+
wg._f = f;
|
|
31311
|
+
wgFeatures.push(wg);
|
|
30985
31312
|
}
|
|
30986
31313
|
}
|
|
30987
|
-
this.featureMap.set(key, feature);
|
|
30988
31314
|
}
|
|
30989
31315
|
}
|
|
31316
|
+
this.#wgValues[windowFunction] = {values: wgFeatures, bpPerPixel};
|
|
31317
|
+
return wgFeatures
|
|
30990
31318
|
}
|
|
30991
31319
|
}
|
|
30992
31320
|
|
|
30993
|
-
|
|
30994
|
-
if (this.featureMap) {
|
|
30995
|
-
return this.featureMap.get(term.toUpperCase())
|
|
30996
|
-
}
|
|
31321
|
+
}
|
|
30997
31322
|
|
|
31323
|
+
function decodeBedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
|
|
31324
|
+
|
|
31325
|
+
const nPositions = tile.nPositions;
|
|
31326
|
+
const starts = tile.start;
|
|
31327
|
+
const ends = tile.end;
|
|
31328
|
+
const data = tile.data[0]; // Single track for now
|
|
31329
|
+
for (let i = 0; i < nPositions; i++) {
|
|
31330
|
+
const s = starts[i];
|
|
31331
|
+
const e = ends[i];
|
|
31332
|
+
if (e < bpStart) continue
|
|
31333
|
+
if (s > bpEnd) break
|
|
31334
|
+
features.push({
|
|
31335
|
+
chr: chr,
|
|
31336
|
+
start: s,
|
|
31337
|
+
end: e,
|
|
31338
|
+
value: data[i]
|
|
31339
|
+
});
|
|
30998
31340
|
}
|
|
30999
31341
|
}
|
|
31000
31342
|
|
|
31343
|
+
function decodeVaryTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
|
|
31344
|
+
|
|
31345
|
+
const nPositions = tile.nPositions;
|
|
31346
|
+
const starts = tile.start;
|
|
31347
|
+
const span = tile.span;
|
|
31348
|
+
const data = tile.data[0]; // Single track for now
|
|
31349
|
+
for (let i = 0; i < nPositions; i++) {
|
|
31350
|
+
const s = starts[i];
|
|
31351
|
+
const e = s + span;
|
|
31352
|
+
if (e < bpStart) continue
|
|
31353
|
+
if (s > bpEnd) break
|
|
31354
|
+
features.push({
|
|
31355
|
+
chr: chr,
|
|
31356
|
+
start: s,
|
|
31357
|
+
end: e,
|
|
31358
|
+
value: data[i]
|
|
31359
|
+
});
|
|
31360
|
+
}
|
|
31361
|
+
}
|
|
31362
|
+
|
|
31363
|
+
function decodeFixedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
|
|
31364
|
+
|
|
31365
|
+
const nPositions = tile.nPositions;
|
|
31366
|
+
let s = tile.start;
|
|
31367
|
+
const span = tile.span;
|
|
31368
|
+
const data = tile.data[0]; // Single track for now
|
|
31369
|
+
|
|
31370
|
+
for (let i = 0; i < nPositions; i++) {
|
|
31371
|
+
const e = s + span;
|
|
31372
|
+
if (s > bpEnd) break
|
|
31373
|
+
if (e >= bpStart) {
|
|
31374
|
+
if (!Number.isNaN(data[i])) {
|
|
31375
|
+
features.push({
|
|
31376
|
+
chr: chr,
|
|
31377
|
+
start: s,
|
|
31378
|
+
end: e,
|
|
31379
|
+
value: data[i]
|
|
31380
|
+
});
|
|
31381
|
+
}
|
|
31382
|
+
}
|
|
31383
|
+
s = e;
|
|
31384
|
+
}
|
|
31385
|
+
}
|
|
31386
|
+
|
|
31387
|
+
|
|
31388
|
+
var log2 = Math.log(2);
|
|
31389
|
+
|
|
31390
|
+
function zoomLevelForScale$1(chr, bpPerPixel, genome) {
|
|
31391
|
+
|
|
31392
|
+
// Convert bpPerPixel to IGV "zoom" level. This is a bit convoluted, TDF is computed zoom levels assuming
|
|
31393
|
+
// display in a 700 pixel window. The fully zoomed out view of a chromosome is zoom level "0".
|
|
31394
|
+
// Zoom level 1 is magnified 2X, and so forth
|
|
31395
|
+
|
|
31396
|
+
var chrSize = genome.getChromosome(chr).bpLength;
|
|
31397
|
+
|
|
31398
|
+
return Math.ceil(Math.log(Math.max(0, (chrSize / (bpPerPixel * 700)))) / log2)
|
|
31399
|
+
}
|
|
31400
|
+
|
|
31001
31401
|
/**
|
|
31002
31402
|
* A ChromTree parses a UCSC bigbed/bigwig "chromosomeTree" section of the header to produce 2 maps,
|
|
31003
31403
|
* (1) ID -> chromosome names, and its
|
|
@@ -31569,7 +31969,7 @@ class BWReader {
|
|
|
31569
31969
|
if (this.type === "bigwig") {
|
|
31570
31970
|
// Select a biwig "zoom level" appropriate for the current resolution.
|
|
31571
31971
|
const zoomLevelHeaders = await this.getZoomHeaders();
|
|
31572
|
-
let zoomLevelHeader = bpPerPixel ? zoomLevelForScale
|
|
31972
|
+
let zoomLevelHeader = bpPerPixel ? zoomLevelForScale(bpPerPixel, zoomLevelHeaders) : undefined;
|
|
31573
31973
|
if (zoomLevelHeader) {
|
|
31574
31974
|
treeOffset = zoomLevelHeader.indexOffset;
|
|
31575
31975
|
decodeFunction = decodeZoomData;
|
|
@@ -32025,7 +32425,7 @@ function computeStats() {
|
|
|
32025
32425
|
}
|
|
32026
32426
|
}
|
|
32027
32427
|
|
|
32028
|
-
function zoomLevelForScale
|
|
32428
|
+
function zoomLevelForScale(bpPerPixel, zoomLevelHeaders) {
|
|
32029
32429
|
let level;
|
|
32030
32430
|
for (let i = 0; i < zoomLevelHeaders.length; i++) {
|
|
32031
32431
|
const zl = zoomLevelHeaders[i];
|
|
@@ -32213,7 +32613,7 @@ class DataBuffer {
|
|
|
32213
32613
|
class BWSource extends BaseFeatureSource {
|
|
32214
32614
|
|
|
32215
32615
|
queryable = true
|
|
32216
|
-
wgValues = {}
|
|
32616
|
+
#wgValues = {}
|
|
32217
32617
|
windowFunctions = ["mean", "min", "max"]
|
|
32218
32618
|
|
|
32219
32619
|
constructor(config, genome) {
|
|
@@ -32225,12 +32625,15 @@ class BWSource extends BaseFeatureSource {
|
|
|
32225
32625
|
|
|
32226
32626
|
async getFeatures({chr, start, end, bpPerPixel, windowFunction}) {
|
|
32227
32627
|
|
|
32228
|
-
await
|
|
32628
|
+
await this.reader.loadHeader();
|
|
32229
32629
|
const isBigWig = this.reader.type === "bigwig";
|
|
32230
32630
|
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
await this.
|
|
32631
|
+
let features;
|
|
32632
|
+
if ("all" === chr.toLowerCase()) {
|
|
32633
|
+
features = isBigWig ? await this.getWGValues(windowFunction, bpPerPixel) : [];
|
|
32634
|
+
} else {
|
|
32635
|
+
features = await this.reader.readFeatures(chr, start, chr, end, bpPerPixel, windowFunction);
|
|
32636
|
+
}
|
|
32234
32637
|
|
|
32235
32638
|
if (!isBigWig) {
|
|
32236
32639
|
pack(features);
|
|
@@ -32246,26 +32649,25 @@ class BWSource extends BaseFeatureSource {
|
|
|
32246
32649
|
if (this.reader.type === "bigwig") {
|
|
32247
32650
|
return -1
|
|
32248
32651
|
} else {
|
|
32249
|
-
return this.reader.featureDensity ?
|
|
32652
|
+
return this.reader.featureDensity ? Math.floor(10000 / this.reader.featureDensity) : -1
|
|
32250
32653
|
}
|
|
32251
32654
|
|
|
32252
32655
|
}
|
|
32253
32656
|
|
|
32254
|
-
async getWGValues(windowFunction) {
|
|
32657
|
+
async getWGValues(windowFunction, bpPerPixel) {
|
|
32255
32658
|
|
|
32256
|
-
const numberOfBins = 1000; // This doesn't need to be precise
|
|
32257
32659
|
const genome = this.genome;
|
|
32258
|
-
|
|
32259
|
-
if (
|
|
32260
|
-
return
|
|
32660
|
+
const cached = this.#wgValues[windowFunction];
|
|
32661
|
+
if (cached && cached.bpPerPixel > 0.8 * bpPerPixel && cached.bpPerPixel < 1.2 * bpPerPixel) {
|
|
32662
|
+
return cached.values
|
|
32261
32663
|
} else {
|
|
32262
32664
|
|
|
32263
|
-
const bpPerPixel = genome.getGenomeLength() / numberOfBins;
|
|
32264
32665
|
const features = await this.reader.readWGFeatures(bpPerPixel, windowFunction);
|
|
32265
32666
|
let wgValues = [];
|
|
32266
32667
|
for (let f of features) {
|
|
32267
32668
|
const chr = f.chr;
|
|
32268
32669
|
const offset = genome.getCumulativeOffset(chr);
|
|
32670
|
+
if (undefined === offset) continue
|
|
32269
32671
|
const wgFeature = Object.assign({}, f);
|
|
32270
32672
|
wgFeature.chr = "all";
|
|
32271
32673
|
wgFeature.start = offset + f.start;
|
|
@@ -32274,7 +32676,7 @@ class BWSource extends BaseFeatureSource {
|
|
|
32274
32676
|
wgValues.push(wgFeature);
|
|
32275
32677
|
}
|
|
32276
32678
|
wgValues.sort((a, b) => a.start - b.start);
|
|
32277
|
-
this
|
|
32679
|
+
this.#wgValues[windowFunction] = {values: wgValues, bpPerPixel};
|
|
32278
32680
|
return wgValues
|
|
32279
32681
|
}
|
|
32280
32682
|
}
|
|
@@ -32296,658 +32698,780 @@ class BWSource extends BaseFeatureSource {
|
|
|
32296
32698
|
}
|
|
32297
32699
|
}
|
|
32298
32700
|
|
|
32299
|
-
|
|
32300
|
-
|
|
32301
|
-
|
|
32302
|
-
|
|
32303
|
-
|
|
32304
|
-
|
|
32305
|
-
|
|
32306
|
-
|
|
32307
|
-
|
|
32308
|
-
|
|
32309
|
-
|
|
32310
|
-
|
|
32311
|
-
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32315
|
-
*
|
|
32316
|
-
|
|
32317
|
-
|
|
32318
|
-
|
|
32319
|
-
|
|
32320
|
-
|
|
32321
|
-
|
|
32322
|
-
|
|
32323
|
-
|
|
32701
|
+
const shim = .01;
|
|
32702
|
+
const colorStripWidth = 4;
|
|
32703
|
+
const axesXOffset = colorStripWidth + 1;
|
|
32704
|
+
function paintAxis(ctx, width, height, colorOrUndefined) {
|
|
32705
|
+
|
|
32706
|
+
if (undefined === this.dataRange || undefined === this.dataRange.max || undefined === this.dataRange.min) {
|
|
32707
|
+
return
|
|
32708
|
+
}
|
|
32709
|
+
|
|
32710
|
+
IGVGraphics.fillRect(ctx, 0, 0, width, height, { fillStyle: 'white' });
|
|
32711
|
+
if (colorOrUndefined) {
|
|
32712
|
+
IGVGraphics.fillRect(ctx, width - colorStripWidth - 2, 0, colorStripWidth, height, { fillStyle: colorOrUndefined });
|
|
32713
|
+
}
|
|
32714
|
+
|
|
32715
|
+
const flipAxis = (undefined === this.flipAxis) ? false : this.flipAxis;
|
|
32716
|
+
|
|
32717
|
+
const xTickStart = 0.95 * width - 8 - axesXOffset;
|
|
32718
|
+
const xTickEnd = 0.95 * width - axesXOffset;
|
|
32719
|
+
|
|
32720
|
+
const properties =
|
|
32721
|
+
{
|
|
32722
|
+
font: 'normal 10px Arial',
|
|
32723
|
+
textAlign: 'right',
|
|
32724
|
+
fillStyle: 'black',
|
|
32725
|
+
strokeStyle: 'black',
|
|
32726
|
+
};
|
|
32727
|
+
|
|
32728
|
+
// tick
|
|
32729
|
+
IGVGraphics.strokeLine(ctx, xTickStart, shim * height, xTickEnd, shim * height, properties);
|
|
32730
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.min : this.dataRange.max), xTickStart + 4, shim * height + 12, properties);
|
|
32731
|
+
|
|
32732
|
+
const y = (1.0 - shim) * height;
|
|
32733
|
+
|
|
32734
|
+
// tick
|
|
32735
|
+
IGVGraphics.strokeLine(ctx, xTickStart, y, xTickEnd, y, properties);
|
|
32736
|
+
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max : this.dataRange.min), xTickStart + 4, y - 4, properties);
|
|
32737
|
+
|
|
32738
|
+
// vertical axis
|
|
32739
|
+
IGVGraphics.strokeLine(ctx, xTickEnd, shim * height, xTickEnd, y, properties);
|
|
32740
|
+
|
|
32741
|
+
function prettyPrint(number) {
|
|
32742
|
+
|
|
32743
|
+
if (number === 0) {
|
|
32744
|
+
return "0"
|
|
32745
|
+
} else if (Math.abs(number) >= 10) {
|
|
32746
|
+
return number.toFixed()
|
|
32747
|
+
} else if (Math.abs(number) >= 1) {
|
|
32748
|
+
return number.toFixed(1)
|
|
32749
|
+
} else if (Math.abs(number) >= 0.1) {
|
|
32750
|
+
return number.toFixed(2)
|
|
32751
|
+
} else {
|
|
32752
|
+
return number.toExponential(1)
|
|
32753
|
+
}
|
|
32754
|
+
}
|
|
32755
|
+
}
|
|
32756
|
+
|
|
32757
|
+
const DEFAULT_COLOR$2 = 'rgb(150, 150, 150)';
|
|
32758
|
+
|
|
32759
|
+
|
|
32760
|
+
class WigTrack extends TrackBase {
|
|
32761
|
+
|
|
32762
|
+
static defaults = {
|
|
32763
|
+
height: 50,
|
|
32764
|
+
flipAxis: false,
|
|
32765
|
+
logScale: false,
|
|
32766
|
+
windowFunction: 'mean',
|
|
32767
|
+
graphType: 'bar',
|
|
32768
|
+
normalize: undefined,
|
|
32769
|
+
scaleFactor: undefined,
|
|
32770
|
+
overflowColor: `rgb(255, 32, 255)`,
|
|
32771
|
+
baselineColor: 'lightGray',
|
|
32772
|
+
summarize: true
|
|
32773
|
+
}
|
|
32774
|
+
|
|
32775
|
+
constructor(config, browser) {
|
|
32776
|
+
super(config, browser);
|
|
32777
|
+
}
|
|
32778
|
+
|
|
32779
|
+
init(config) {
|
|
32780
|
+
|
|
32781
|
+
super.init(config);
|
|
32782
|
+
|
|
32783
|
+
this.type = "wig";
|
|
32784
|
+
this.featureType = 'numeric';
|
|
32785
|
+
this.resolutionAware = true;
|
|
32786
|
+
this.paintAxis = paintAxis;
|
|
32787
|
+
|
|
32788
|
+
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
32789
|
+
if (config.featureSource) {
|
|
32790
|
+
this.featureSource = config.featureSource;
|
|
32791
|
+
delete config.featureSource;
|
|
32792
|
+
} else if ("bigwig" === format) {
|
|
32793
|
+
this.featureSource = new BWSource(config, this.browser.genome);
|
|
32794
|
+
} else if ("tdf" === format) {
|
|
32795
|
+
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
32796
|
+
} else {
|
|
32797
|
+
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
32798
|
+
}
|
|
32799
|
+
|
|
32800
|
+
|
|
32801
|
+
// Override autoscale default
|
|
32802
|
+
if (config.max === undefined || config.autoscale === true) {
|
|
32803
|
+
this.autoscale = true;
|
|
32804
|
+
} else {
|
|
32805
|
+
this.dataRange = {
|
|
32806
|
+
min: config.min || 0,
|
|
32807
|
+
max: config.max
|
|
32808
|
+
};
|
|
32809
|
+
}
|
|
32810
|
+
}
|
|
32811
|
+
|
|
32812
|
+
async postInit() {
|
|
32813
|
+
const header = await this.getHeader();
|
|
32814
|
+
if (this.disposed) return // This track was removed during async load
|
|
32815
|
+
if (header) this.setTrackProperties(header);
|
|
32816
|
+
}
|
|
32817
|
+
|
|
32818
|
+
async getFeatures(chr, start, end, bpPerPixel) {
|
|
32819
|
+
|
|
32820
|
+
const windowFunction = this.windowFunction;
|
|
32821
|
+
|
|
32822
|
+
const features = await this.featureSource.getFeatures({
|
|
32823
|
+
chr,
|
|
32824
|
+
start,
|
|
32825
|
+
end,
|
|
32826
|
+
bpPerPixel,
|
|
32827
|
+
visibilityWindow: this.visibilityWindow,
|
|
32828
|
+
windowFunction
|
|
32829
|
+
});
|
|
32830
|
+
if (this.normalize && this.featureSource.normalizationFactor) {
|
|
32831
|
+
const scaleFactor = this.featureSource.normalizationFactor;
|
|
32832
|
+
for (let f of features) {
|
|
32833
|
+
f.value *= scaleFactor;
|
|
32834
|
+
}
|
|
32835
|
+
}
|
|
32836
|
+
if (this.scaleFactor) {
|
|
32837
|
+
const scaleFactor = this.scaleFactor;
|
|
32838
|
+
for (let f of features) {
|
|
32839
|
+
f.value *= scaleFactor;
|
|
32840
|
+
}
|
|
32841
|
+
}
|
|
32324
32842
|
|
|
32325
|
-
|
|
32843
|
+
// Summarize features to current resolution. This needs to be done here, rather than in the "draw" function,
|
|
32844
|
+
// for group autoscale to work.
|
|
32845
|
+
if (this.summarize && ("mean" === windowFunction || "min" === windowFunction || "max" === windowFunction)) {
|
|
32846
|
+
return summarizeData(features, start, bpPerPixel, windowFunction)
|
|
32847
|
+
} else {
|
|
32848
|
+
return features
|
|
32849
|
+
}
|
|
32850
|
+
}
|
|
32326
32851
|
|
|
32327
|
-
|
|
32852
|
+
menuItemList() {
|
|
32853
|
+
const items = [];
|
|
32328
32854
|
|
|
32329
|
-
|
|
32330
|
-
|
|
32331
|
-
this.genome = genome;
|
|
32332
|
-
this.path = config.url;
|
|
32333
|
-
this.groupCache = {};
|
|
32334
|
-
this.datasetCache = {};
|
|
32335
|
-
}
|
|
32855
|
+
if (this.flipAxis !== undefined) {
|
|
32856
|
+
items.push('<hr>');
|
|
32336
32857
|
|
|
32858
|
+
function click() {
|
|
32859
|
+
this.flipAxis = !this.flipAxis;
|
|
32860
|
+
this.trackView.repaintViews();
|
|
32861
|
+
}
|
|
32337
32862
|
|
|
32338
|
-
|
|
32863
|
+
items.push({label: 'Flip y-axis', click});
|
|
32864
|
+
}
|
|
32339
32865
|
|
|
32340
|
-
if
|
|
32341
|
-
|
|
32866
|
+
if(this.featureSource.windowFunctions) {
|
|
32867
|
+
items.push(...this.wigSummarizationItems());
|
|
32342
32868
|
}
|
|
32343
32869
|
|
|
32344
|
-
|
|
32345
|
-
let binaryParser = new BinaryParser$1(new DataView(data));
|
|
32346
|
-
this.magic = binaryParser.getInt();
|
|
32347
|
-
this.version = binaryParser.getInt();
|
|
32348
|
-
this.indexPos = binaryParser.getLong();
|
|
32349
|
-
this.indexSize = binaryParser.getInt();
|
|
32350
|
-
binaryParser.getInt();
|
|
32870
|
+
items.push(...this.numericDataMenuItems());
|
|
32351
32871
|
|
|
32872
|
+
return items
|
|
32873
|
+
}
|
|
32352
32874
|
|
|
32353
|
-
|
|
32354
|
-
let nWindowFunctions = binaryParser.getInt();
|
|
32355
|
-
this.windowFunctions = [];
|
|
32356
|
-
while (nWindowFunctions-- > 0) {
|
|
32357
|
-
this.windowFunctions.push(binaryParser.getString());
|
|
32358
|
-
}
|
|
32359
|
-
}
|
|
32875
|
+
wigSummarizationItems() {
|
|
32360
32876
|
|
|
32361
|
-
|
|
32362
|
-
this.trackLine = binaryParser.getString();
|
|
32877
|
+
const windowFunctions = this.featureSource.windowFunctions;
|
|
32363
32878
|
|
|
32364
|
-
|
|
32365
|
-
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
this.genomeID = binaryParser.getString();
|
|
32370
|
-
this.flags = binaryParser.getInt();
|
|
32371
|
-
this.compressed = (this.flags & GZIP_FLAG) !== 0;
|
|
32879
|
+
const menuItems = [];
|
|
32880
|
+
menuItems.push('<hr/>');
|
|
32881
|
+
menuItems.push("<div>Windowing function</div>");
|
|
32882
|
+
for (const wf of windowFunctions) {
|
|
32883
|
+
const object = $$1(createCheckbox(wf, this.windowFunction === wf));
|
|
32372
32884
|
|
|
32373
|
-
|
|
32374
|
-
|
|
32375
|
-
|
|
32376
|
-
start: this.indexPos,
|
|
32377
|
-
size: this.indexSize
|
|
32885
|
+
function clickHandler() {
|
|
32886
|
+
this.windowFunction = wf;
|
|
32887
|
+
this.trackView.updateViews();
|
|
32378
32888
|
}
|
|
32379
|
-
}));
|
|
32380
|
-
binaryParser = new BinaryParser$1(new DataView(data));
|
|
32381
|
-
this.datasetIndex = {};
|
|
32382
|
-
let nEntries = binaryParser.getInt();
|
|
32383
|
-
while (nEntries-- > 0) {
|
|
32384
|
-
const name = binaryParser.getString();
|
|
32385
|
-
const pos = binaryParser.getLong();
|
|
32386
|
-
const size = binaryParser.getInt();
|
|
32387
|
-
this.datasetIndex[name] = {position: pos, size: size};
|
|
32388
|
-
}
|
|
32389
32889
|
|
|
32390
|
-
|
|
32391
|
-
nEntries = binaryParser.getInt();
|
|
32392
|
-
while (nEntries-- > 0) {
|
|
32393
|
-
const name = binaryParser.getString();
|
|
32394
|
-
const pos = binaryParser.getLong();
|
|
32395
|
-
const size = binaryParser.getInt();
|
|
32396
|
-
this.groupIndex[name] = {position: pos, size: size};
|
|
32890
|
+
menuItems.push({object, click: clickHandler});
|
|
32397
32891
|
}
|
|
32398
32892
|
|
|
32399
|
-
return
|
|
32893
|
+
return menuItems
|
|
32400
32894
|
}
|
|
32401
32895
|
|
|
32402
|
-
async readDataset(chr, windowFunction, zoom) {
|
|
32403
32896
|
|
|
32404
|
-
|
|
32897
|
+
async getHeader() {
|
|
32405
32898
|
|
|
32406
|
-
if (this.
|
|
32407
|
-
|
|
32899
|
+
if (typeof this.featureSource.getHeader === "function") {
|
|
32900
|
+
this.header = await this.featureSource.getHeader();
|
|
32901
|
+
}
|
|
32902
|
+
return this.header
|
|
32903
|
+
}
|
|
32408
32904
|
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
|
|
32412
|
-
|
|
32905
|
+
// TODO: refactor to igvUtils.js
|
|
32906
|
+
getScaleFactor(min, max, height, logScale) {
|
|
32907
|
+
const minValue = (logScale === true) ? ((min < 0) ? -Math.log10(Math.abs(min) + 1) : Math.log10(Math.abs(min) + 1)) : min;
|
|
32908
|
+
const maxValue = (logScale === true) ? Math.log10(Math.abs(max) + 1) : max;
|
|
32909
|
+
const scale = height / (maxValue - minValue);
|
|
32910
|
+
return scale
|
|
32911
|
+
}
|
|
32413
32912
|
|
|
32414
|
-
|
|
32415
|
-
|
|
32416
|
-
|
|
32417
|
-
} else {
|
|
32418
|
-
dsName = "/" + chr + "/z" + zoomString + wf;
|
|
32419
|
-
}
|
|
32420
|
-
const indexEntry = this.datasetIndex[dsName];
|
|
32913
|
+
computeYPixelValue(yValue, yScaleFactor) {
|
|
32914
|
+
return (this.flipAxis ? (yValue - this.dataRange.min) : (this.dataRange.max - yValue)) * yScaleFactor
|
|
32915
|
+
}
|
|
32421
32916
|
|
|
32422
|
-
|
|
32423
|
-
|
|
32424
|
-
|
|
32917
|
+
computeYPixelValueInLogScale(yValue, yScaleFactor) {
|
|
32918
|
+
let maxValue = this.dataRange.max;
|
|
32919
|
+
let minValue = this.dataRange.min;
|
|
32920
|
+
minValue = (minValue < 0) ? -Math.log10(Math.abs(minValue) + 1) : Math.log10(Math.abs(minValue) + 1);
|
|
32921
|
+
maxValue = (maxValue < 0) ? -Math.log10(Math.abs(maxValue) + 1) : Math.log10(Math.abs(maxValue) + 1);
|
|
32922
|
+
|
|
32923
|
+
yValue = (yValue < 0) ? -Math.log10(Math.abs(yValue) +1) : Math.log10(yValue + 1);
|
|
32924
|
+
return ((this.flipAxis ? (yValue - minValue) : (maxValue - yValue)) * yScaleFactor)
|
|
32925
|
+
}
|
|
32425
32926
|
|
|
32426
|
-
|
|
32427
|
-
range: {
|
|
32428
|
-
start: indexEntry.position,
|
|
32429
|
-
size: indexEntry.size
|
|
32430
|
-
}
|
|
32431
|
-
}));
|
|
32927
|
+
draw(options) {
|
|
32432
32928
|
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32929
|
+
const features = options.features;
|
|
32930
|
+
const ctx = options.context;
|
|
32931
|
+
const bpPerPixel = options.bpPerPixel;
|
|
32932
|
+
const bpStart = options.bpStart;
|
|
32933
|
+
const pixelWidth = options.pixelWidth;
|
|
32934
|
+
const pixelHeight = options.pixelHeight - 1;
|
|
32935
|
+
const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
|
|
32936
|
+
|
|
32937
|
+
const scaleFactor = this.getScaleFactor(this.dataRange.min, this.dataRange.max, pixelHeight, this.logScale);
|
|
32938
|
+
const yScale = (yValue) => this.logScale
|
|
32939
|
+
? this.computeYPixelValueInLogScale(yValue, scaleFactor)
|
|
32940
|
+
: this.computeYPixelValue(yValue, scaleFactor);
|
|
32436
32941
|
|
|
32437
|
-
|
|
32438
|
-
let nAttributes = binaryParser.getInt();
|
|
32439
|
-
const attributes = {};
|
|
32440
|
-
while (nAttributes-- > 0) {
|
|
32441
|
-
attributes[binaryParser.getString()] = binaryParser.getString();
|
|
32442
|
-
}
|
|
32443
|
-
const dataType = binaryParser.getString();
|
|
32444
|
-
const tileWidth = binaryParser.getFloat();
|
|
32445
|
-
let nTiles = binaryParser.getInt();
|
|
32446
|
-
const tiles = [];
|
|
32447
|
-
while (nTiles-- > 0) {
|
|
32448
|
-
tiles.push({position: binaryParser.getLong(), size: binaryParser.getInt()});
|
|
32449
|
-
}
|
|
32942
|
+
if (features && features.length > 0) {
|
|
32450
32943
|
|
|
32451
|
-
|
|
32452
|
-
name: dsName,
|
|
32453
|
-
attributes: attributes,
|
|
32454
|
-
dataType: dataType,
|
|
32455
|
-
tileWidth: tileWidth,
|
|
32456
|
-
tiles: tiles
|
|
32457
|
-
};
|
|
32944
|
+
if (this.dataRange.min === undefined) this.dataRange.min = 0;
|
|
32458
32945
|
|
|
32459
|
-
|
|
32460
|
-
|
|
32461
|
-
|
|
32462
|
-
}
|
|
32946
|
+
// Max can be less than min if config.min is set but max left to autoscale. If that's the case there is
|
|
32947
|
+
// nothing to paint.
|
|
32948
|
+
if (this.dataRange.max > this.dataRange.min) {
|
|
32463
32949
|
|
|
32464
|
-
|
|
32950
|
+
let lastPixelEnd = -1;
|
|
32951
|
+
let lastY;
|
|
32952
|
+
const y0 = yScale(0);
|
|
32465
32953
|
|
|
32466
|
-
|
|
32467
|
-
const rootGroup = this.groupCache["/"];
|
|
32468
|
-
if (rootGroup) {
|
|
32469
|
-
return rootGroup
|
|
32470
|
-
} else {
|
|
32954
|
+
for (let f of features) {
|
|
32471
32955
|
|
|
32472
|
-
|
|
32473
|
-
|
|
32474
|
-
const maxZoomString = group["maxZoom"];
|
|
32956
|
+
if (f.end < bpStart) continue
|
|
32957
|
+
if (f.start > bpEnd) break
|
|
32475
32958
|
|
|
32476
|
-
|
|
32477
|
-
|
|
32478
|
-
this.maxZoom = Number(maxZoomString);
|
|
32479
|
-
}
|
|
32959
|
+
const x = (f.start - bpStart) / bpPerPixel;
|
|
32960
|
+
if (isNaN(x)) continue
|
|
32480
32961
|
|
|
32481
|
-
|
|
32482
|
-
if (totalCountString) {
|
|
32483
|
-
group.totalCount = Number(totalCountString);
|
|
32484
|
-
}
|
|
32962
|
+
let y = yScale(f.value);
|
|
32485
32963
|
|
|
32486
|
-
|
|
32487
|
-
|
|
32488
|
-
if (names) {
|
|
32489
|
-
names.split(",").forEach(function (chr) {
|
|
32490
|
-
const canonicalName = genome.getChromosomeName(chr);
|
|
32491
|
-
chrAliasTable[canonicalName] = chr;
|
|
32492
|
-
});
|
|
32493
|
-
}
|
|
32494
|
-
this.chrAliasTable = chrAliasTable;
|
|
32964
|
+
const rectEnd = (f.end - bpStart) / bpPerPixel;
|
|
32965
|
+
const width = rectEnd - x;
|
|
32495
32966
|
|
|
32496
|
-
|
|
32497
|
-
return group
|
|
32498
|
-
}
|
|
32499
|
-
}
|
|
32967
|
+
const color = options.alpha ? IGVColor.addAlpha(this.getColorForFeature(f), options.alpha) : this.getColorForFeature(f);
|
|
32500
32968
|
|
|
32501
|
-
|
|
32969
|
+
if (this.graphType === "line") {
|
|
32970
|
+
if (lastY !== undefined) {
|
|
32971
|
+
IGVGraphics.strokeLine(ctx, lastPixelEnd, lastY, x, y, {
|
|
32972
|
+
"fillStyle": color,
|
|
32973
|
+
"strokeStyle": color
|
|
32974
|
+
});
|
|
32975
|
+
}
|
|
32976
|
+
IGVGraphics.strokeLine(ctx, x, y, x + width, y, {"fillStyle": color, "strokeStyle": color});
|
|
32977
|
+
} else if (this.graphType === "points") {
|
|
32978
|
+
const pointSize = this.config.pointSize || 3;
|
|
32979
|
+
const px = x + width / 2;
|
|
32980
|
+
IGVGraphics.fillCircle(ctx, px, y, pointSize / 2, {"fillStyle": color, "strokeStyle": color});
|
|
32502
32981
|
|
|
32503
|
-
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
|
|
32982
|
+
if (f.value > this.dataRange.max) {
|
|
32983
|
+
IGVGraphics.fillCircle(ctx, px, pointSize / 2, pointSize / 2, 3, {fillStyle: this.overflowColor});
|
|
32984
|
+
} else if (f.value < this.dataRange.min) {
|
|
32985
|
+
IGVGraphics.fillCircle(ctx, px, pixelHeight - pointSize / 2, pointSize / 2, 3, {fillStyle: this.overflowColor});
|
|
32986
|
+
}
|
|
32507
32987
|
|
|
32508
|
-
|
|
32509
|
-
|
|
32510
|
-
|
|
32511
|
-
|
|
32512
|
-
|
|
32988
|
+
} else {
|
|
32989
|
+
// Default graph type (bar)
|
|
32990
|
+
const height = Math.min(pixelHeight, y - y0);
|
|
32991
|
+
IGVGraphics.fillRect(ctx, x, y0, width, height, {fillStyle: color});
|
|
32992
|
+
if (f.value > this.dataRange.max) {
|
|
32993
|
+
IGVGraphics.fillRect(ctx, x, 0, width, 3, {fillStyle: this.overflowColor});
|
|
32994
|
+
} else if (f.value < this.dataRange.min) {
|
|
32995
|
+
IGVGraphics.fillRect(ctx, x, pixelHeight - 2, width, 3, {fillStyle: this.overflowColor});
|
|
32996
|
+
}
|
|
32513
32997
|
|
|
32514
|
-
|
|
32515
|
-
|
|
32516
|
-
|
|
32517
|
-
size: indexEntry.size
|
|
32998
|
+
}
|
|
32999
|
+
lastPixelEnd = x + width;
|
|
33000
|
+
lastY = y;
|
|
32518
33001
|
}
|
|
32519
|
-
}));
|
|
32520
33002
|
|
|
32521
|
-
|
|
32522
|
-
|
|
33003
|
+
// If the track includes negative values draw a baseline
|
|
33004
|
+
if (this.dataRange.min < 0) {
|
|
33005
|
+
let maxValue = this.dataRange.max;
|
|
33006
|
+
let minValue = this.dataRange.min;
|
|
33007
|
+
minValue = (this.logScale === true) ? ((minValue < 0) ? -Math.log10(Math.abs(minValue) + 1) : Math.log10(Math.abs(minValue) + 1)) : minValue;
|
|
33008
|
+
maxValue = (this.logScale === true) ? ((maxValue < 0) ? -Math.log10(Math.abs(maxValue) + 1) : Math.log10(Math.abs(maxValue) + 1)) : maxValue;
|
|
33009
|
+
const ratio = maxValue / (maxValue - minValue);
|
|
33010
|
+
const basepx = this.flipAxis ? (1 - ratio) * pixelHeight : ratio * pixelHeight;
|
|
33011
|
+
IGVGraphics.strokeLine(ctx, 0, basepx, options.pixelWidth, basepx, {strokeStyle: this.baselineColor});
|
|
33012
|
+
}
|
|
32523
33013
|
}
|
|
33014
|
+
}
|
|
32524
33015
|
|
|
32525
|
-
|
|
32526
|
-
|
|
32527
|
-
let
|
|
32528
|
-
|
|
32529
|
-
|
|
32530
|
-
|
|
32531
|
-
|
|
33016
|
+
// Draw guidelines
|
|
33017
|
+
if (this.config.hasOwnProperty('guideLines')) {
|
|
33018
|
+
for (let line of this.config.guideLines) {
|
|
33019
|
+
if (line.hasOwnProperty('color') && line.hasOwnProperty('y') && line.hasOwnProperty('dotted')) {
|
|
33020
|
+
let y = yScale(line.y);
|
|
33021
|
+
let props = {
|
|
33022
|
+
'strokeStyle': line['color'],
|
|
33023
|
+
'strokeWidth': 2
|
|
33024
|
+
};
|
|
33025
|
+
if (line['dotted']) IGVGraphics.dashedLine(options.context, 0, y, options.pixelWidth, y, 5, props);
|
|
33026
|
+
else IGVGraphics.strokeLine(options.context, 0, y, options.pixelWidth, y, props);
|
|
33027
|
+
}
|
|
32532
33028
|
}
|
|
32533
|
-
this.groupCache[name] = group;
|
|
32534
|
-
return group
|
|
32535
33029
|
}
|
|
32536
33030
|
}
|
|
32537
33031
|
|
|
32538
|
-
|
|
33032
|
+
popupData(clickState, features) {
|
|
32539
33033
|
|
|
32540
|
-
|
|
32541
|
-
return a.position - b.position
|
|
32542
|
-
});
|
|
33034
|
+
if (features === undefined) features = this.clickedFeatures(clickState);
|
|
32543
33035
|
|
|
32544
|
-
|
|
32545
|
-
return idx.size > 0
|
|
32546
|
-
});
|
|
33036
|
+
if (features && features.length > 0) {
|
|
32547
33037
|
|
|
32548
|
-
|
|
32549
|
-
|
|
32550
|
-
}
|
|
33038
|
+
const genomicLocation = clickState.genomicLocation;
|
|
33039
|
+
const popupData = [];
|
|
32551
33040
|
|
|
32552
|
-
|
|
33041
|
+
// Sort features based on distance from click
|
|
33042
|
+
features.sort(function (a, b) {
|
|
33043
|
+
const distA = Math.abs((a.start + a.end) / 2 - genomicLocation);
|
|
33044
|
+
const distB = Math.abs((b.start + b.end) / 2 - genomicLocation);
|
|
33045
|
+
return distA - distB
|
|
33046
|
+
});
|
|
32553
33047
|
|
|
32554
|
-
|
|
33048
|
+
// Display closest 10
|
|
33049
|
+
const displayFeatures = features.length > 10 ? features.slice(0, 10) : features;
|
|
32555
33050
|
|
|
32556
|
-
|
|
33051
|
+
// Resort in ascending order
|
|
33052
|
+
displayFeatures.sort(function (a, b) {
|
|
33053
|
+
return a.start - b.start
|
|
33054
|
+
});
|
|
32557
33055
|
|
|
32558
|
-
|
|
32559
|
-
|
|
32560
|
-
|
|
32561
|
-
|
|
33056
|
+
for (let selectedFeature of displayFeatures) {
|
|
33057
|
+
if (selectedFeature) {
|
|
33058
|
+
if (popupData.length > 0) {
|
|
33059
|
+
popupData.push('<hr/>');
|
|
33060
|
+
}
|
|
33061
|
+
let posString = (selectedFeature.end - selectedFeature.start) === 1 ?
|
|
33062
|
+
numberFormatter$1(Math.floor(selectedFeature.start) + 1)
|
|
33063
|
+
: numberFormatter$1(Math.floor(selectedFeature.start) + 1) + "-" + numberFormatter$1(Math.floor(selectedFeature.end));
|
|
33064
|
+
popupData.push({name: "Position:", value: posString});
|
|
33065
|
+
popupData.push({
|
|
33066
|
+
name: "Value: ",
|
|
33067
|
+
value: numberFormatter$1(selectedFeature.value.toFixed(4))
|
|
33068
|
+
});
|
|
32562
33069
|
}
|
|
32563
|
-
}));
|
|
32564
|
-
|
|
32565
|
-
const tileData = this.compressed ? inflate_1$3(data).buffer : data;
|
|
32566
|
-
|
|
32567
|
-
const binaryParser = new BinaryParser$1(new DataView(tileData));
|
|
32568
|
-
const type = binaryParser.getString();
|
|
32569
|
-
let tile;
|
|
32570
|
-
switch (type) {
|
|
32571
|
-
case "fixedStep":
|
|
32572
|
-
tile = createFixedStep(binaryParser, nTracks);
|
|
32573
|
-
break
|
|
32574
|
-
case "variableStep":
|
|
32575
|
-
tile = createVariableStep(binaryParser, nTracks);
|
|
32576
|
-
break
|
|
32577
|
-
case "bed":
|
|
32578
|
-
case "bedWithName":
|
|
32579
|
-
tile = createBed(binaryParser, nTracks, type);
|
|
32580
|
-
break
|
|
32581
|
-
default:
|
|
32582
|
-
throw "Unknown tile type: " + type
|
|
32583
33070
|
}
|
|
32584
|
-
|
|
32585
|
-
|
|
32586
|
-
}
|
|
32587
|
-
return tiles
|
|
32588
|
-
}
|
|
32589
|
-
|
|
32590
|
-
async readTile(indexEntry, nTracks) {
|
|
32591
|
-
|
|
32592
|
-
let data = await igvxhr.loadArrayBuffer(this.path, buildOptions(this.config, {
|
|
32593
|
-
range: {
|
|
32594
|
-
start: indexEntry.position,
|
|
32595
|
-
size: indexEntry.size
|
|
33071
|
+
if (displayFeatures.length < features.length) {
|
|
33072
|
+
popupData.push("<hr/>...");
|
|
32596
33073
|
}
|
|
32597
|
-
}));
|
|
32598
33074
|
|
|
32599
|
-
|
|
32600
|
-
const plain = inflate_1$3(data);
|
|
32601
|
-
data = plain.buffer;
|
|
32602
|
-
}
|
|
33075
|
+
return popupData
|
|
32603
33076
|
|
|
32604
|
-
|
|
32605
|
-
|
|
32606
|
-
switch (type) {
|
|
32607
|
-
case "fixedStep":
|
|
32608
|
-
return createFixedStep(binaryParser, nTracks)
|
|
32609
|
-
case "variableStep":
|
|
32610
|
-
return createVariableStep(binaryParser, nTracks)
|
|
32611
|
-
case "bed":
|
|
32612
|
-
case "bedWithName":
|
|
32613
|
-
return createBed(binaryParser, nTracks, type)
|
|
32614
|
-
default:
|
|
32615
|
-
throw "Unknown tile type: " + type
|
|
33077
|
+
} else {
|
|
33078
|
+
return []
|
|
32616
33079
|
}
|
|
32617
33080
|
}
|
|
32618
33081
|
|
|
32619
|
-
|
|
33082
|
+
get supportsWholeGenome() {
|
|
33083
|
+
return !this.config.indexURL && this.config.supportsWholeGenome !== false
|
|
33084
|
+
}
|
|
32620
33085
|
|
|
32621
|
-
|
|
32622
|
-
|
|
32623
|
-
|
|
32624
|
-
|
|
33086
|
+
/**
|
|
33087
|
+
* Return color for feature.
|
|
33088
|
+
* @param feature
|
|
33089
|
+
* @returns {string}
|
|
33090
|
+
*/
|
|
32625
33091
|
|
|
32626
|
-
|
|
32627
|
-
|
|
32628
|
-
|
|
32629
|
-
let np = nPositions;
|
|
32630
|
-
const dtrack = [];
|
|
32631
|
-
while (np-- > 0) {
|
|
32632
|
-
dtrack.push(binaryParser.getFloat());
|
|
32633
|
-
}
|
|
32634
|
-
data.push(dtrack);
|
|
33092
|
+
getColorForFeature(f) {
|
|
33093
|
+
let c = (f.value < 0 && this.altColor) ? this.altColor : this.color || DEFAULT_COLOR$2;
|
|
33094
|
+
return (typeof c === "function") ? c(f.value) : c
|
|
32635
33095
|
}
|
|
32636
33096
|
|
|
32637
|
-
|
|
32638
|
-
|
|
32639
|
-
|
|
32640
|
-
|
|
32641
|
-
|
|
32642
|
-
nTracks: nTracks,
|
|
32643
|
-
nPositions: nPositions
|
|
33097
|
+
/**
|
|
33098
|
+
* Called when the track is removed. Do any needed cleanup here
|
|
33099
|
+
*/
|
|
33100
|
+
dispose() {
|
|
33101
|
+
this.trackView = undefined;
|
|
32644
33102
|
}
|
|
32645
|
-
}
|
|
32646
33103
|
|
|
32647
|
-
|
|
33104
|
+
}
|
|
32648
33105
|
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
33106
|
+
/**
|
|
33107
|
+
* Summarize wig data in bins of size "bpPerPixel" with the given window function.
|
|
33108
|
+
*
|
|
33109
|
+
* @param features wig (numeric) data -- features cannot overlap, and are in ascending order by start position
|
|
33110
|
+
* @param startBP bp start position for computing binned data
|
|
33111
|
+
* @param bpPerPixel bp per pixel (bin)
|
|
33112
|
+
* @param windowFunction mean, min, or max
|
|
33113
|
+
* @returns {*|*[]}
|
|
33114
|
+
*/
|
|
33115
|
+
function summarizeData(features, startBP, bpPerPixel, windowFunction = "mean") {
|
|
32653
33116
|
|
|
32654
|
-
|
|
32655
|
-
|
|
32656
|
-
start.push(binaryParser.getInt());
|
|
33117
|
+
if (bpPerPixel <= 1 || !features || features.length === 0) {
|
|
33118
|
+
return features
|
|
32657
33119
|
}
|
|
32658
|
-
binaryParser.getInt(); // # of samples, ignored but should === nTracks
|
|
32659
33120
|
|
|
32660
|
-
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
33121
|
+
// Assume features are sorted by position. Wig features cannot overlap. Note, UCSC "reductionLevel" == bpPerPixel
|
|
33122
|
+
const chr = features[0].chr;
|
|
33123
|
+
const binSize = bpPerPixel;
|
|
33124
|
+
const summaryFeatures = [];
|
|
33125
|
+
|
|
33126
|
+
const finishBin = (bin) => {
|
|
33127
|
+
const start = startBP + bin.bin * binSize;
|
|
33128
|
+
const end = start + binSize;
|
|
33129
|
+
let value;
|
|
33130
|
+
switch (windowFunction) {
|
|
33131
|
+
case "mean":
|
|
33132
|
+
value = bin.sumData / bin.count;
|
|
33133
|
+
break
|
|
33134
|
+
case "max":
|
|
33135
|
+
value = bin.max;
|
|
33136
|
+
break
|
|
33137
|
+
case "min":
|
|
33138
|
+
value = bin.min;
|
|
33139
|
+
break
|
|
33140
|
+
default:
|
|
33141
|
+
throw Error(`Unknown window function: ${windowFunction}`)
|
|
32667
33142
|
}
|
|
32668
|
-
|
|
32669
|
-
|
|
33143
|
+
const description = `${windowFunction} of ${bin.count} values`;
|
|
33144
|
+
summaryFeatures.push({chr, start, end, value, description});
|
|
33145
|
+
};
|
|
32670
33146
|
|
|
32671
|
-
|
|
32672
|
-
|
|
32673
|
-
tileStart: tileStart,
|
|
32674
|
-
span: span,
|
|
32675
|
-
start: start,
|
|
32676
|
-
data: data,
|
|
32677
|
-
nTracks: nTracks,
|
|
32678
|
-
nPositions: nPositions
|
|
32679
|
-
}
|
|
32680
|
-
}
|
|
33147
|
+
let currentBinData;
|
|
33148
|
+
for (let f of features) {
|
|
32681
33149
|
|
|
32682
|
-
|
|
33150
|
+
// Loop through bins this feature overlaps, updating the weighted sum for each bin or min/max,
|
|
33151
|
+
// depending on window function
|
|
33152
|
+
let startBin = Math.floor((f.start - startBP) / binSize);
|
|
33153
|
+
const endBin = Math.floor((f.end - startBP) / binSize);
|
|
33154
|
+
|
|
33155
|
+
if (currentBinData && startBin === currentBinData.bin) {
|
|
33156
|
+
currentBinData.add(f);
|
|
33157
|
+
startBin++;
|
|
33158
|
+
}
|
|
32683
33159
|
|
|
32684
|
-
|
|
33160
|
+
if (!currentBinData || endBin > currentBinData.bin) {
|
|
32685
33161
|
|
|
32686
|
-
|
|
32687
|
-
|
|
32688
|
-
|
|
32689
|
-
start.push(binaryParser.getInt());
|
|
32690
|
-
}
|
|
33162
|
+
if(currentBinData) {
|
|
33163
|
+
finishBin(currentBinData);
|
|
33164
|
+
}
|
|
32691
33165
|
|
|
32692
|
-
|
|
32693
|
-
|
|
32694
|
-
|
|
32695
|
-
|
|
32696
|
-
|
|
33166
|
+
// Feature stretches across multiple bins.
|
|
33167
|
+
if (endBin > startBin) {
|
|
33168
|
+
const end = startBP + endBin * binSize;
|
|
33169
|
+
summaryFeatures.push({chr, start: f.start, end, value: f.value});
|
|
33170
|
+
}
|
|
32697
33171
|
|
|
32698
|
-
|
|
32699
|
-
const data = [];
|
|
32700
|
-
let nt = nTracks;
|
|
32701
|
-
while (nt-- > 0) {
|
|
32702
|
-
let np = nPositions;
|
|
32703
|
-
const dtrack = [];
|
|
32704
|
-
while (np-- > 0) {
|
|
32705
|
-
dtrack.push(binaryParser.getFloat());
|
|
33172
|
+
currentBinData = new SummaryBinData(endBin, f);
|
|
32706
33173
|
}
|
|
32707
|
-
|
|
33174
|
+
|
|
33175
|
+
}
|
|
33176
|
+
if(currentBinData) {
|
|
33177
|
+
finishBin(currentBinData);
|
|
32708
33178
|
}
|
|
32709
33179
|
|
|
32710
|
-
|
|
32711
|
-
|
|
32712
|
-
|
|
32713
|
-
|
|
32714
|
-
|
|
33180
|
+
// Consolidate
|
|
33181
|
+
const c = [];
|
|
33182
|
+
let lastFeature = summaryFeatures[0];
|
|
33183
|
+
for (let f of summaryFeatures) {
|
|
33184
|
+
if (lastFeature.value === f.value && f.start <= lastFeature.end) {
|
|
33185
|
+
lastFeature.end = f.end;
|
|
33186
|
+
} else {
|
|
33187
|
+
c.push(lastFeature);
|
|
33188
|
+
lastFeature = f;
|
|
32715
33189
|
}
|
|
32716
33190
|
}
|
|
33191
|
+
c.push(lastFeature);
|
|
33192
|
+
|
|
33193
|
+
return c
|
|
32717
33194
|
|
|
32718
|
-
return {
|
|
32719
|
-
type: type,
|
|
32720
|
-
start: start,
|
|
32721
|
-
end: end,
|
|
32722
|
-
data: data,
|
|
32723
|
-
nTracks: nTracks,
|
|
32724
|
-
nPositions: nPositions
|
|
32725
|
-
}
|
|
32726
33195
|
}
|
|
32727
33196
|
|
|
32728
|
-
|
|
33197
|
+
class SummaryBinData {
|
|
33198
|
+
constructor(bin, feature) {
|
|
33199
|
+
this.bin = bin;
|
|
33200
|
+
this.sumData = feature.value;
|
|
33201
|
+
this.count = 1;
|
|
33202
|
+
this.min = feature.value;
|
|
33203
|
+
this.max = feature.value;
|
|
33204
|
+
}
|
|
33205
|
+
|
|
33206
|
+
add(feature) {
|
|
33207
|
+
this.sumData += feature.value;
|
|
33208
|
+
this.max = Math.max(feature.value, this.max);
|
|
33209
|
+
this.min = Math.min(feature.value, this.min);
|
|
33210
|
+
this.count++;
|
|
33211
|
+
}
|
|
32729
33212
|
|
|
32730
|
-
|
|
32731
|
-
|
|
32732
|
-
for (let i = 1; i < tiles.length; i++) {
|
|
32733
|
-
const t = tiles[i];
|
|
32734
|
-
if (t.position > current.position + current.size) {
|
|
32735
|
-
consolidated.push(current);
|
|
32736
|
-
current = t;
|
|
32737
|
-
} else {
|
|
32738
|
-
current.size = t.position + t.size - current.position;
|
|
32739
|
-
}
|
|
33213
|
+
get mean() {
|
|
33214
|
+
return this.sumData / this.count
|
|
32740
33215
|
}
|
|
32741
|
-
consolidated.push(current);
|
|
32742
|
-
return consolidated
|
|
32743
33216
|
}
|
|
32744
33217
|
|
|
32745
|
-
|
|
32746
|
-
|
|
32747
|
-
|
|
32748
|
-
*
|
|
32749
|
-
* Author: Jim Robinson
|
|
32750
|
-
*
|
|
32751
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32752
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
32753
|
-
* in the Software without restriction, including without limitation the rights
|
|
32754
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
32755
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
32756
|
-
* furnished to do so, subject to the following conditions:
|
|
32757
|
-
*
|
|
32758
|
-
* The above copyright notice and this permission notice shall be included in
|
|
32759
|
-
* all copies or substantial portions of the Software.
|
|
32760
|
-
*
|
|
33218
|
+
const DEFAULT_MAX_WG_COUNT = 10000;
|
|
33219
|
+
|
|
33220
|
+
/**
|
|
33221
|
+
* feature source for "bed like" files (tab or whitespace delimited files with 1 feature per line: bed, gff, vcf, etc)
|
|
32761
33222
|
*
|
|
32762
|
-
*
|
|
32763
|
-
*
|
|
32764
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32765
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
32766
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32767
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
32768
|
-
* THE SOFTWARE.
|
|
33223
|
+
* @param config
|
|
33224
|
+
* @constructor
|
|
32769
33225
|
*/
|
|
33226
|
+
class TextFeatureSource extends BaseFeatureSource {
|
|
32770
33227
|
|
|
32771
|
-
class TDFSource extends BaseFeatureSource {
|
|
32772
|
-
|
|
32773
|
-
searchable = false
|
|
32774
33228
|
constructor(config, genome) {
|
|
33229
|
+
|
|
32775
33230
|
super(genome);
|
|
33231
|
+
|
|
33232
|
+
this.config = config || {};
|
|
32776
33233
|
this.genome = genome;
|
|
32777
|
-
this.
|
|
32778
|
-
this.
|
|
32779
|
-
|
|
33234
|
+
this.sourceType = (config.sourceType === undefined ? "file" : config.sourceType);
|
|
33235
|
+
this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
|
|
33236
|
+
this.windowFunctions = ["mean", "min", "max", "none"];
|
|
32780
33237
|
|
|
32781
|
-
|
|
33238
|
+
const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "biggenepred", "bignarrowpeak", "tdf"]);
|
|
32782
33239
|
|
|
32783
|
-
|
|
32784
|
-
|
|
32785
|
-
|
|
32786
|
-
|
|
32787
|
-
|
|
32788
|
-
|
|
32789
|
-
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
|
|
32793
|
-
|
|
32794
|
-
|
|
32795
|
-
|
|
32796
|
-
|
|
32797
|
-
|
|
32798
|
-
|
|
32799
|
-
|
|
32800
|
-
|
|
32801
|
-
|
|
32802
|
-
|
|
32803
|
-
|
|
32804
|
-
|
|
33240
|
+
this.queryable = config.indexURL || config.queryable === true; // False by default, unless explicitly set
|
|
33241
|
+
if (config.reader) {
|
|
33242
|
+
// Explicit reader implementation
|
|
33243
|
+
this.reader = config.reader;
|
|
33244
|
+
this.queryable = config.queryable !== false;
|
|
33245
|
+
} else if (config.sourceType === "ga4gh") {
|
|
33246
|
+
throw Error("Unsupported source type 'ga4gh'")
|
|
33247
|
+
} else if ((config.type === "eqtl" || config.type === "qtl") && config.sourceType === "gtex-ws") {
|
|
33248
|
+
this.reader = new GtexReader(config);
|
|
33249
|
+
this.queryable = true;
|
|
33250
|
+
} else if ("htsget" === config.sourceType) {
|
|
33251
|
+
this.reader = new HtsgetVariantReader(config, genome);
|
|
33252
|
+
this.queryable = true;
|
|
33253
|
+
} else if (config.sourceType === 'ucscservice') {
|
|
33254
|
+
this.reader = new UCSCServiceReader(config.source);
|
|
33255
|
+
this.queryable = true;
|
|
33256
|
+
} else if (config.sourceType === 'custom') {
|
|
33257
|
+
this.reader = new CustomServiceReader(config.source);
|
|
33258
|
+
this.queryable = false !== config.source.queryable;
|
|
33259
|
+
} else if ('service' === config.sourceType) {
|
|
33260
|
+
this.reader = new FeatureFileReader(config, genome);
|
|
33261
|
+
this.queryable = true;
|
|
33262
|
+
} else {
|
|
33263
|
+
// File of some type (i.e. not a webservice)
|
|
33264
|
+
this.reader = new FeatureFileReader(config, genome);
|
|
33265
|
+
if (config.queryable !== undefined) {
|
|
33266
|
+
this.queryable = config.queryable;
|
|
33267
|
+
} else if (queryableFormats.has(config.format) || this.reader.indexed) {
|
|
33268
|
+
this.queryable = true;
|
|
33269
|
+
} else ;
|
|
33270
|
+
}
|
|
33271
|
+
|
|
33272
|
+
// Flag indicating if features loaded by this source can be searched for by name or attribute, true by default
|
|
33273
|
+
this.searchable = config.searchable !== false;
|
|
33274
|
+
|
|
33275
|
+
}
|
|
33276
|
+
|
|
33277
|
+
async defaultVisibilityWindow() {
|
|
33278
|
+
if (this.reader && typeof this.reader.defaultVisibilityWindow === 'function') {
|
|
33279
|
+
return this.reader.defaultVisibilityWindow()
|
|
33280
|
+
}
|
|
33281
|
+
}
|
|
32805
33282
|
|
|
33283
|
+
async trackType() {
|
|
33284
|
+
const header = await this.getHeader();
|
|
33285
|
+
if (header) {
|
|
33286
|
+
return header.type
|
|
32806
33287
|
} else {
|
|
32807
|
-
return
|
|
33288
|
+
return undefined // Convention for unknown or unspecified
|
|
32808
33289
|
}
|
|
32809
33290
|
}
|
|
32810
|
-
async _getFeatures(chr, start, end, bpPerPixel, windowFunction) {
|
|
32811
|
-
const genomicInterval = new GenomicInterval(chr, start, end);
|
|
32812
|
-
const genome = this.genome;
|
|
32813
33291
|
|
|
33292
|
+
async getHeader() {
|
|
33293
|
+
if (!this.header) {
|
|
32814
33294
|
|
|
32815
|
-
|
|
32816
|
-
|
|
32817
|
-
|
|
32818
|
-
|
|
32819
|
-
|
|
32820
|
-
|
|
33295
|
+
if (this.reader && typeof this.reader.readHeader === "function") {
|
|
33296
|
+
const header = await this.reader.readHeader();
|
|
33297
|
+
if (header) {
|
|
33298
|
+
this.header = header;
|
|
33299
|
+
if (header.format) {
|
|
33300
|
+
this.config.format = header.format;
|
|
33301
|
+
}
|
|
33302
|
+
} else {
|
|
33303
|
+
this.header = {};
|
|
32821
33304
|
}
|
|
33305
|
+
} else {
|
|
33306
|
+
this.header = {};
|
|
32822
33307
|
}
|
|
32823
33308
|
}
|
|
33309
|
+
return this.header
|
|
33310
|
+
}
|
|
32824
33311
|
|
|
32825
|
-
|
|
32826
|
-
|
|
32827
|
-
|
|
32828
|
-
|
|
32829
|
-
|
|
32830
|
-
|
|
33312
|
+
/**
|
|
33313
|
+
* Required function for all data source objects. Fetches features for the
|
|
33314
|
+
* range requested.
|
|
33315
|
+
*
|
|
33316
|
+
* This function is quite complex due to the variety of reader types backing it, some indexed, some queryable,
|
|
33317
|
+
* some not.
|
|
33318
|
+
*
|
|
33319
|
+
* @param chr
|
|
33320
|
+
* @param start
|
|
33321
|
+
* @param end
|
|
33322
|
+
* @param bpPerPixel
|
|
33323
|
+
*/
|
|
33324
|
+
async getFeatures({chr, start, end, bpPerPixel, visibilityWindow, windowFunction}) {
|
|
32831
33325
|
|
|
32832
|
-
const
|
|
32833
|
-
|
|
32834
|
-
|
|
32835
|
-
|
|
33326
|
+
const isWholeGenome = ("all" === chr.toLowerCase());
|
|
33327
|
+
|
|
33328
|
+
start = start || 0;
|
|
33329
|
+
end = end || Number.MAX_SAFE_INTEGER;
|
|
33330
|
+
|
|
33331
|
+
// Various conditions that can require a feature load
|
|
33332
|
+
// * view is "whole genome" but no features are loaded
|
|
33333
|
+
// * cache is disabled
|
|
33334
|
+
// * cache does not contain requested range
|
|
33335
|
+
// const containsRange = this.featureCache.containsRange(new GenomicInterval(queryChr, start, end))
|
|
33336
|
+
if ((isWholeGenome && !this.wgFeatures && this.supportsWholeGenome()) ||
|
|
33337
|
+
this.config.disableCache ||
|
|
33338
|
+
!this.featureCache ||
|
|
33339
|
+
!this.featureCache.containsRange(new GenomicInterval(chr, start, end))) {
|
|
33340
|
+
await this.loadFeatures(chr, start, end, visibilityWindow);
|
|
32836
33341
|
}
|
|
32837
33342
|
|
|
32838
|
-
|
|
32839
|
-
|
|
32840
|
-
|
|
32841
|
-
|
|
32842
|
-
|
|
32843
|
-
|
|
32844
|
-
|
|
32845
|
-
|
|
32846
|
-
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
|
|
32850
|
-
decodeVaryTile(tile, chr, start, end, bpPerPixel, features);
|
|
32851
|
-
break
|
|
32852
|
-
case "fixedStep":
|
|
32853
|
-
decodeFixedTile(tile, chr, start, end, bpPerPixel, features);
|
|
32854
|
-
break
|
|
32855
|
-
default:
|
|
32856
|
-
throw ("Unknown tile type: " + tile.type)
|
|
33343
|
+
if (isWholeGenome) {
|
|
33344
|
+
if (!this.wgFeatures) {
|
|
33345
|
+
if (this.supportsWholeGenome()) {
|
|
33346
|
+
if("wig" === this.config.type) {
|
|
33347
|
+
const allWgFeatures = await computeWGFeatures(this.featureCache.getAllFeatures(), this.genome, 1000000);
|
|
33348
|
+
this.wgFeatures = summarizeData(allWgFeatures, 0, bpPerPixel, windowFunction);
|
|
33349
|
+
} else {
|
|
33350
|
+
this.wgFeatures = await computeWGFeatures(this.featureCache.getAllFeatures(), this.genome, this.maxWGCount);
|
|
33351
|
+
}
|
|
33352
|
+
} else {
|
|
33353
|
+
this.wgFeatures = [];
|
|
33354
|
+
}
|
|
32857
33355
|
}
|
|
33356
|
+
return this.wgFeatures
|
|
33357
|
+
} else {
|
|
33358
|
+
return this.featureCache.queryFeatures(chr, start, end)
|
|
32858
33359
|
}
|
|
32859
|
-
features.sort(function (a, b) {
|
|
32860
|
-
return a.start - b.start
|
|
32861
|
-
});
|
|
32862
|
-
|
|
32863
|
-
return features
|
|
32864
33360
|
}
|
|
32865
33361
|
|
|
32866
|
-
|
|
32867
|
-
return
|
|
33362
|
+
async findFeatures(fn) {
|
|
33363
|
+
return this.featureCache ? this.featureCache.findFeatures(fn) : []
|
|
32868
33364
|
}
|
|
32869
33365
|
|
|
32870
|
-
|
|
32871
|
-
return this.
|
|
33366
|
+
supportsWholeGenome() {
|
|
33367
|
+
return !this.queryable // queryable (indexed, web services) sources don't support whole genome view
|
|
32872
33368
|
}
|
|
32873
|
-
}
|
|
32874
33369
|
|
|
32875
|
-
|
|
32876
|
-
|
|
32877
|
-
|
|
32878
|
-
|
|
32879
|
-
|
|
32880
|
-
|
|
32881
|
-
|
|
32882
|
-
const s = starts[i];
|
|
32883
|
-
const e = ends[i];
|
|
32884
|
-
if (e < bpStart) continue
|
|
32885
|
-
if (s > bpEnd) break
|
|
32886
|
-
features.push({
|
|
32887
|
-
chr: chr,
|
|
32888
|
-
start: s,
|
|
32889
|
-
end: e,
|
|
32890
|
-
value: data[i]
|
|
32891
|
-
});
|
|
33370
|
+
// TODO -- experimental, will only work for non-indexed sources
|
|
33371
|
+
getAllFeatures() {
|
|
33372
|
+
if (this.queryable || !this.featureCache) { // queryable sources don't support all features
|
|
33373
|
+
return []
|
|
33374
|
+
} else {
|
|
33375
|
+
return this.featureCache.getAllFeatures()
|
|
33376
|
+
}
|
|
32892
33377
|
}
|
|
32893
|
-
}
|
|
32894
33378
|
|
|
32895
|
-
function decodeVaryTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
|
|
32896
33379
|
|
|
32897
|
-
|
|
32898
|
-
const starts = tile.start;
|
|
32899
|
-
const span = tile.span;
|
|
32900
|
-
const data = tile.data[0]; // Single track for now
|
|
32901
|
-
for (let i = 0; i < nPositions; i++) {
|
|
32902
|
-
const s = starts[i];
|
|
32903
|
-
const e = s + span;
|
|
32904
|
-
if (e < bpStart) continue
|
|
32905
|
-
if (s > bpEnd) break
|
|
32906
|
-
features.push({
|
|
32907
|
-
chr: chr,
|
|
32908
|
-
start: s,
|
|
32909
|
-
end: e,
|
|
32910
|
-
value: data[i]
|
|
32911
|
-
});
|
|
32912
|
-
}
|
|
32913
|
-
}
|
|
33380
|
+
async loadFeatures(chr, start, end, visibilityWindow) {
|
|
32914
33381
|
|
|
32915
|
-
|
|
33382
|
+
await this.getHeader();
|
|
32916
33383
|
|
|
32917
|
-
|
|
32918
|
-
|
|
32919
|
-
|
|
32920
|
-
const data = tile.data[0]; // Single track for now
|
|
33384
|
+
const reader = this.reader;
|
|
33385
|
+
let intervalStart = start;
|
|
33386
|
+
let intervalEnd = end;
|
|
32921
33387
|
|
|
32922
|
-
|
|
32923
|
-
|
|
32924
|
-
if (
|
|
32925
|
-
|
|
32926
|
-
|
|
32927
|
-
|
|
32928
|
-
|
|
32929
|
-
|
|
32930
|
-
|
|
32931
|
-
|
|
32932
|
-
|
|
33388
|
+
// chr aliasing
|
|
33389
|
+
let queryChr = chr;
|
|
33390
|
+
if (!this.chrAliasManager && this.reader && this.reader.sequenceNames) {
|
|
33391
|
+
this.chrAliasManager = new ChromAliasManager(this.reader.sequenceNames, this.genome);
|
|
33392
|
+
}
|
|
33393
|
+
if (this.chrAliasManager) {
|
|
33394
|
+
queryChr = await this.chrAliasManager.getAliasName(chr);
|
|
33395
|
+
}
|
|
33396
|
+
|
|
33397
|
+
// Use visibility window to potentially expand query interval.
|
|
33398
|
+
// This can save re-queries as we zoom out. Visibility window <= 0 is a special case
|
|
33399
|
+
// indicating whole chromosome should be read at once.
|
|
33400
|
+
if ((!visibilityWindow || visibilityWindow <= 0) && this.config.expandQuery !== false) {
|
|
33401
|
+
// Whole chromosome
|
|
33402
|
+
const chromosome = this.genome ? this.genome.getChromosome(queryChr) : undefined;
|
|
33403
|
+
intervalStart = 0;
|
|
33404
|
+
intervalEnd = Math.max(chromosome ? chromosome.bpLength : Number.MAX_SAFE_INTEGER, end);
|
|
33405
|
+
} else if (visibilityWindow > (end - start) && this.config.expandQuery !== false) {
|
|
33406
|
+
let expansionWindow = Math.min(4.1 * (end - start), visibilityWindow);
|
|
33407
|
+
if(this.config.minQuerySize && expansionWindow < this.config.minQuerySize) {
|
|
33408
|
+
expansionWindow = this.config.minQuerySize;
|
|
32933
33409
|
}
|
|
33410
|
+
intervalStart = Math.max(0, (start + end - expansionWindow) / 2);
|
|
33411
|
+
intervalEnd = intervalStart + expansionWindow;
|
|
32934
33412
|
}
|
|
32935
|
-
s = e;
|
|
32936
|
-
}
|
|
32937
|
-
}
|
|
32938
33413
|
|
|
33414
|
+
let features = await reader.readFeatures(queryChr, intervalStart, intervalEnd);
|
|
33415
|
+
if (this.queryable === undefined) {
|
|
33416
|
+
this.queryable = reader.indexed;
|
|
33417
|
+
}
|
|
32939
33418
|
|
|
32940
|
-
|
|
33419
|
+
const genomicInterval = this.queryable ?
|
|
33420
|
+
new GenomicInterval(chr, intervalStart, intervalEnd) :
|
|
33421
|
+
undefined;
|
|
32941
33422
|
|
|
32942
|
-
|
|
33423
|
+
if (features) {
|
|
32943
33424
|
|
|
32944
|
-
|
|
32945
|
-
|
|
32946
|
-
|
|
33425
|
+
// Assign overlapping features to rows
|
|
33426
|
+
if (this.config.format !== "wig" && this.config.type !== "junctions") {
|
|
33427
|
+
const maxRows = this.config.maxRows || Number.MAX_SAFE_INTEGER;
|
|
33428
|
+
packFeatures(features, maxRows);
|
|
33429
|
+
}
|
|
32947
33430
|
|
|
32948
|
-
|
|
33431
|
+
// Note - replacing previous cache with new one. genomicInterval is optional (might be undefined => includes all features)
|
|
33432
|
+
this.featureCache = new FeatureCache$1(features, this.genome, genomicInterval);
|
|
32949
33433
|
|
|
32950
|
-
|
|
33434
|
+
// If track is marked "searchable"< cache features by name -- use this with caution, memory intensive
|
|
33435
|
+
if (this.searchable) {
|
|
33436
|
+
this.addFeaturesToDB(features, this.config);
|
|
33437
|
+
}
|
|
33438
|
+
} else {
|
|
33439
|
+
this.featureCache = new FeatureCache$1([], genomicInterval); // Empty cache
|
|
33440
|
+
}
|
|
33441
|
+
}
|
|
33442
|
+
|
|
33443
|
+
addFeaturesToDB(featureList, config) {
|
|
33444
|
+
if (!this.featureMap) {
|
|
33445
|
+
this.featureMap = new Map();
|
|
33446
|
+
}
|
|
33447
|
+
const searchableFields = config.searchableFields || ["name", "transcript_id", "gene_id", "gene_name", "id"];
|
|
33448
|
+
for (let feature of featureList) {
|
|
33449
|
+
for (let field of searchableFields) {
|
|
33450
|
+
let key;
|
|
33451
|
+
if (typeof feature.getAttributeValue === 'function') {
|
|
33452
|
+
key = feature.getAttributeValue(field);
|
|
33453
|
+
}
|
|
33454
|
+
if (key) {
|
|
33455
|
+
key = key.replaceAll(' ', '+').toUpperCase();
|
|
33456
|
+
// If feature is already present keep largest one
|
|
33457
|
+
if (this.featureMap.has(key)) {
|
|
33458
|
+
const f2 = this.featureMap.get(key);
|
|
33459
|
+
if (feature.end - feature.start < f2.end - f2.start) {
|
|
33460
|
+
continue
|
|
33461
|
+
}
|
|
33462
|
+
}
|
|
33463
|
+
this.featureMap.set(key, feature);
|
|
33464
|
+
}
|
|
33465
|
+
}
|
|
33466
|
+
}
|
|
33467
|
+
}
|
|
33468
|
+
|
|
33469
|
+
search(term) {
|
|
33470
|
+
if (this.featureMap) {
|
|
33471
|
+
return this.featureMap.get(term.toUpperCase())
|
|
33472
|
+
}
|
|
33473
|
+
|
|
33474
|
+
}
|
|
32951
33475
|
}
|
|
32952
33476
|
|
|
32953
33477
|
/*
|
|
@@ -34239,7 +34763,7 @@ function renderFusionJuncSpan(feature, bpStart, xScale, pixelHeight, ctx) {
|
|
|
34239
34763
|
}
|
|
34240
34764
|
}
|
|
34241
34765
|
|
|
34242
|
-
const DEFAULT_COLOR$
|
|
34766
|
+
const DEFAULT_COLOR$1 = 'rgb(0, 0, 150)';
|
|
34243
34767
|
|
|
34244
34768
|
|
|
34245
34769
|
class FeatureTrack extends TrackBase {
|
|
@@ -34736,7 +35260,7 @@ class FeatureTrack extends TrackBase {
|
|
|
34736
35260
|
|
|
34737
35261
|
// If no explicit setting use the default
|
|
34738
35262
|
if (!color) {
|
|
34739
|
-
color = DEFAULT_COLOR$
|
|
35263
|
+
color = DEFAULT_COLOR$1; // Track default
|
|
34740
35264
|
}
|
|
34741
35265
|
|
|
34742
35266
|
if (feature.alpha && feature.alpha !== 1) {
|
|
@@ -37863,7 +38387,6 @@ function indentLevel(str) {
|
|
|
37863
38387
|
}
|
|
37864
38388
|
|
|
37865
38389
|
const DEFAULT_GENOMES_URL = "https://igv.org/genomes/genomes.json";
|
|
37866
|
-
const BACKUP_GENOMES_URL = "https://s3.amazonaws.com/igv.org.genomes/genomes.json";
|
|
37867
38390
|
|
|
37868
38391
|
const GenomeUtils = {
|
|
37869
38392
|
|
|
@@ -37875,21 +38398,9 @@ const GenomeUtils = {
|
|
|
37875
38398
|
|
|
37876
38399
|
// Get default genomes
|
|
37877
38400
|
if (config.loadDefaultGenomes !== false) {
|
|
37878
|
-
|
|
37879
|
-
|
|
37880
|
-
|
|
37881
|
-
processJson(jsonArray);
|
|
37882
|
-
} catch (e) {
|
|
37883
|
-
console.error(e);
|
|
37884
|
-
try {
|
|
37885
|
-
const url = BACKUP_GENOMES_URL;
|
|
37886
|
-
const jsonArray = await igvxhr.loadJson(url, {});
|
|
37887
|
-
processJson(jsonArray);
|
|
37888
|
-
} catch (e) {
|
|
37889
|
-
console.error(e);
|
|
37890
|
-
console.warn("Errors loading default genome definitions.");
|
|
37891
|
-
}
|
|
37892
|
-
}
|
|
38401
|
+
const url = DEFAULT_GENOMES_URL;
|
|
38402
|
+
const jsonArray = await igvxhr.loadJson(url, {timeout: 5000});
|
|
38403
|
+
processJson(jsonArray);
|
|
37893
38404
|
}
|
|
37894
38405
|
|
|
37895
38406
|
// Add user-defined genomes
|
|
@@ -37954,7 +38465,7 @@ const GenomeUtils = {
|
|
|
37954
38465
|
}
|
|
37955
38466
|
}
|
|
37956
38467
|
|
|
37957
|
-
if(!reference) {
|
|
38468
|
+
if (!reference) {
|
|
37958
38469
|
alert.present(new Error(`Unknown genome id: ${genomeID}`), undefined);
|
|
37959
38470
|
}
|
|
37960
38471
|
}
|
|
@@ -41532,62 +42043,6 @@ const sampleNameButtonLabel =
|
|
|
41532
42043
|
</g>
|
|
41533
42044
|
</svg>`;
|
|
41534
42045
|
|
|
41535
|
-
const shim = .01;
|
|
41536
|
-
const colorStripWidth = 4;
|
|
41537
|
-
const axesXOffset = colorStripWidth + 1;
|
|
41538
|
-
function paintAxis(ctx, width, height, colorOrUndefined) {
|
|
41539
|
-
|
|
41540
|
-
if (undefined === this.dataRange || undefined === this.dataRange.max || undefined === this.dataRange.min) {
|
|
41541
|
-
return
|
|
41542
|
-
}
|
|
41543
|
-
|
|
41544
|
-
IGVGraphics.fillRect(ctx, 0, 0, width, height, { fillStyle: 'white' });
|
|
41545
|
-
if (colorOrUndefined) {
|
|
41546
|
-
IGVGraphics.fillRect(ctx, width - colorStripWidth - 2, 0, colorStripWidth, height, { fillStyle: colorOrUndefined });
|
|
41547
|
-
}
|
|
41548
|
-
|
|
41549
|
-
const flipAxis = (undefined === this.flipAxis) ? false : this.flipAxis;
|
|
41550
|
-
|
|
41551
|
-
const xTickStart = 0.95 * width - 8 - axesXOffset;
|
|
41552
|
-
const xTickEnd = 0.95 * width - axesXOffset;
|
|
41553
|
-
|
|
41554
|
-
const properties =
|
|
41555
|
-
{
|
|
41556
|
-
font: 'normal 10px Arial',
|
|
41557
|
-
textAlign: 'right',
|
|
41558
|
-
fillStyle: 'black',
|
|
41559
|
-
strokeStyle: 'black',
|
|
41560
|
-
};
|
|
41561
|
-
|
|
41562
|
-
// tick
|
|
41563
|
-
IGVGraphics.strokeLine(ctx, xTickStart, shim * height, xTickEnd, shim * height, properties);
|
|
41564
|
-
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.min : this.dataRange.max), xTickStart + 4, shim * height + 12, properties);
|
|
41565
|
-
|
|
41566
|
-
const y = (1.0 - shim) * height;
|
|
41567
|
-
|
|
41568
|
-
// tick
|
|
41569
|
-
IGVGraphics.strokeLine(ctx, xTickStart, y, xTickEnd, y, properties);
|
|
41570
|
-
IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max : this.dataRange.min), xTickStart + 4, y - 4, properties);
|
|
41571
|
-
|
|
41572
|
-
// vertical axis
|
|
41573
|
-
IGVGraphics.strokeLine(ctx, xTickEnd, shim * height, xTickEnd, y, properties);
|
|
41574
|
-
|
|
41575
|
-
function prettyPrint(number) {
|
|
41576
|
-
|
|
41577
|
-
if (number === 0) {
|
|
41578
|
-
return "0"
|
|
41579
|
-
} else if (Math.abs(number) >= 10) {
|
|
41580
|
-
return number.toFixed()
|
|
41581
|
-
} else if (Math.abs(number) >= 1) {
|
|
41582
|
-
return number.toFixed(1)
|
|
41583
|
-
} else if (Math.abs(number) >= 0.1) {
|
|
41584
|
-
return number.toFixed(2)
|
|
41585
|
-
} else {
|
|
41586
|
-
return number.toExponential(1)
|
|
41587
|
-
}
|
|
41588
|
-
}
|
|
41589
|
-
}
|
|
41590
|
-
|
|
41591
42046
|
/*
|
|
41592
42047
|
* The MIT License (MIT)
|
|
41593
42048
|
*
|
|
@@ -43183,462 +43638,6 @@ function renderSVGAxis(context, track, axisCanvas, deltaX, deltaY) {
|
|
|
43183
43638
|
|
|
43184
43639
|
}
|
|
43185
43640
|
|
|
43186
|
-
const DEFAULT_COLOR$1 = 'rgb(150, 150, 150)';
|
|
43187
|
-
|
|
43188
|
-
|
|
43189
|
-
class WigTrack extends TrackBase {
|
|
43190
|
-
|
|
43191
|
-
static defaults = {
|
|
43192
|
-
height: 50,
|
|
43193
|
-
flipAxis: false,
|
|
43194
|
-
logScale: false,
|
|
43195
|
-
windowFunction: 'mean',
|
|
43196
|
-
graphType: 'bar',
|
|
43197
|
-
normalize: undefined,
|
|
43198
|
-
scaleFactor: undefined,
|
|
43199
|
-
overflowColor: `rgb(255, 32, 255)`,
|
|
43200
|
-
baselineColor: 'lightGray',
|
|
43201
|
-
summarize: true
|
|
43202
|
-
}
|
|
43203
|
-
|
|
43204
|
-
constructor(config, browser) {
|
|
43205
|
-
super(config, browser);
|
|
43206
|
-
}
|
|
43207
|
-
|
|
43208
|
-
init(config) {
|
|
43209
|
-
|
|
43210
|
-
super.init(config);
|
|
43211
|
-
|
|
43212
|
-
this.type = "wig";
|
|
43213
|
-
this.featureType = 'numeric';
|
|
43214
|
-
this.resolutionAware = true;
|
|
43215
|
-
this.paintAxis = paintAxis;
|
|
43216
|
-
|
|
43217
|
-
const format = config.format ? config.format.toLowerCase() : config.format;
|
|
43218
|
-
if (config.featureSource) {
|
|
43219
|
-
this.featureSource = config.featureSource;
|
|
43220
|
-
delete config.featureSource;
|
|
43221
|
-
} else if ("bigwig" === format) {
|
|
43222
|
-
this.featureSource = new BWSource(config, this.browser.genome);
|
|
43223
|
-
} else if ("tdf" === format) {
|
|
43224
|
-
this.featureSource = new TDFSource(config, this.browser.genome);
|
|
43225
|
-
} else {
|
|
43226
|
-
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
43227
|
-
}
|
|
43228
|
-
|
|
43229
|
-
|
|
43230
|
-
// Override autoscale default
|
|
43231
|
-
if (config.max === undefined || config.autoscale === true) {
|
|
43232
|
-
this.autoscale = true;
|
|
43233
|
-
} else {
|
|
43234
|
-
this.dataRange = {
|
|
43235
|
-
min: config.min || 0,
|
|
43236
|
-
max: config.max
|
|
43237
|
-
};
|
|
43238
|
-
}
|
|
43239
|
-
}
|
|
43240
|
-
|
|
43241
|
-
async postInit() {
|
|
43242
|
-
const header = await this.getHeader();
|
|
43243
|
-
if (this.disposed) return // This track was removed during async load
|
|
43244
|
-
if (header) this.setTrackProperties(header);
|
|
43245
|
-
}
|
|
43246
|
-
|
|
43247
|
-
async getFeatures(chr, start, end, bpPerPixel) {
|
|
43248
|
-
|
|
43249
|
-
const windowFunction = this.windowFunction;
|
|
43250
|
-
|
|
43251
|
-
const features = await this.featureSource.getFeatures({
|
|
43252
|
-
chr,
|
|
43253
|
-
start,
|
|
43254
|
-
end,
|
|
43255
|
-
bpPerPixel,
|
|
43256
|
-
visibilityWindow: this.visibilityWindow,
|
|
43257
|
-
windowFunction
|
|
43258
|
-
});
|
|
43259
|
-
if (this.normalize && this.featureSource.normalizationFactor) {
|
|
43260
|
-
const scaleFactor = this.featureSource.normalizationFactor;
|
|
43261
|
-
for (let f of features) {
|
|
43262
|
-
f.value *= scaleFactor;
|
|
43263
|
-
}
|
|
43264
|
-
}
|
|
43265
|
-
if (this.scaleFactor) {
|
|
43266
|
-
const scaleFactor = this.scaleFactor;
|
|
43267
|
-
for (let f of features) {
|
|
43268
|
-
f.value *= scaleFactor;
|
|
43269
|
-
}
|
|
43270
|
-
}
|
|
43271
|
-
|
|
43272
|
-
// Summarize features to current resolution. This needs to be done here, rather than in the "draw" function,
|
|
43273
|
-
// for group autoscale to work.
|
|
43274
|
-
if (this.summarize && ("mean" === windowFunction || "min" === windowFunction || "max" === windowFunction)) {
|
|
43275
|
-
return summarizeData(features, start, bpPerPixel, windowFunction)
|
|
43276
|
-
} else {
|
|
43277
|
-
return features
|
|
43278
|
-
}
|
|
43279
|
-
}
|
|
43280
|
-
|
|
43281
|
-
menuItemList() {
|
|
43282
|
-
const items = [];
|
|
43283
|
-
|
|
43284
|
-
if (this.flipAxis !== undefined) {
|
|
43285
|
-
items.push('<hr>');
|
|
43286
|
-
|
|
43287
|
-
function click() {
|
|
43288
|
-
this.flipAxis = !this.flipAxis;
|
|
43289
|
-
this.trackView.repaintViews();
|
|
43290
|
-
}
|
|
43291
|
-
|
|
43292
|
-
items.push({label: 'Flip y-axis', click});
|
|
43293
|
-
}
|
|
43294
|
-
|
|
43295
|
-
if(this.featureSource.windowFunctions) {
|
|
43296
|
-
items.push(...this.wigSummarizationItems());
|
|
43297
|
-
}
|
|
43298
|
-
|
|
43299
|
-
items.push(...this.numericDataMenuItems());
|
|
43300
|
-
|
|
43301
|
-
return items
|
|
43302
|
-
}
|
|
43303
|
-
|
|
43304
|
-
wigSummarizationItems() {
|
|
43305
|
-
|
|
43306
|
-
const windowFunctions = this.featureSource.windowFunctions;
|
|
43307
|
-
|
|
43308
|
-
const menuItems = [];
|
|
43309
|
-
menuItems.push('<hr/>');
|
|
43310
|
-
menuItems.push("<div>Windowing function</div>");
|
|
43311
|
-
for (const wf of windowFunctions) {
|
|
43312
|
-
const object = $$1(createCheckbox(wf, this.windowFunction === wf));
|
|
43313
|
-
|
|
43314
|
-
function clickHandler() {
|
|
43315
|
-
this.windowFunction = wf;
|
|
43316
|
-
this.trackView.updateViews();
|
|
43317
|
-
}
|
|
43318
|
-
|
|
43319
|
-
menuItems.push({object, click: clickHandler});
|
|
43320
|
-
}
|
|
43321
|
-
|
|
43322
|
-
return menuItems
|
|
43323
|
-
}
|
|
43324
|
-
|
|
43325
|
-
|
|
43326
|
-
async getHeader() {
|
|
43327
|
-
|
|
43328
|
-
if (typeof this.featureSource.getHeader === "function") {
|
|
43329
|
-
this.header = await this.featureSource.getHeader();
|
|
43330
|
-
}
|
|
43331
|
-
return this.header
|
|
43332
|
-
}
|
|
43333
|
-
|
|
43334
|
-
// TODO: refactor to igvUtils.js
|
|
43335
|
-
getScaleFactor(min, max, height, logScale) {
|
|
43336
|
-
const scale = logScale ? height / (Math.log10(max + 1) - (min <= 0 ? 0 : Math.log10(min + 1))) : height / (max - min);
|
|
43337
|
-
return scale
|
|
43338
|
-
}
|
|
43339
|
-
|
|
43340
|
-
computeYPixelValue(yValue, yScaleFactor) {
|
|
43341
|
-
return (this.flipAxis ? (yValue - this.dataRange.min) : (this.dataRange.max - yValue)) * yScaleFactor
|
|
43342
|
-
}
|
|
43343
|
-
|
|
43344
|
-
computeYPixelValueInLogScale(yValue, yScaleFactor) {
|
|
43345
|
-
let maxValue = this.dataRange.max;
|
|
43346
|
-
let minValue = this.dataRange.min;
|
|
43347
|
-
if (maxValue <= 0) return 0 // TODO:
|
|
43348
|
-
if (minValue <= -1) minValue = 0;
|
|
43349
|
-
minValue = (minValue <= 0) ? 0 : Math.log10(minValue + 1);
|
|
43350
|
-
maxValue = Math.log10(maxValue + 1);
|
|
43351
|
-
yValue = Math.log10(yValue + 1);
|
|
43352
|
-
return ((this.flipAxis ? (yValue - minValue) : (maxValue - yValue)) * yScaleFactor)
|
|
43353
|
-
}
|
|
43354
|
-
|
|
43355
|
-
draw(options) {
|
|
43356
|
-
|
|
43357
|
-
const features = options.features;
|
|
43358
|
-
const ctx = options.context;
|
|
43359
|
-
const bpPerPixel = options.bpPerPixel;
|
|
43360
|
-
const bpStart = options.bpStart;
|
|
43361
|
-
const pixelWidth = options.pixelWidth;
|
|
43362
|
-
const pixelHeight = options.pixelHeight;
|
|
43363
|
-
const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
|
|
43364
|
-
this.color || DEFAULT_COLOR$1;
|
|
43365
|
-
const scaleFactor = this.getScaleFactor(this.dataRange.min, this.dataRange.max, options.pixelHeight, this.logScale);
|
|
43366
|
-
const yScale = (yValue) => this.logScale
|
|
43367
|
-
? this.computeYPixelValueInLogScale(yValue, scaleFactor)
|
|
43368
|
-
: this.computeYPixelValue(yValue, scaleFactor);
|
|
43369
|
-
|
|
43370
|
-
if (features && features.length > 0) {
|
|
43371
|
-
|
|
43372
|
-
if (this.dataRange.min === undefined) this.dataRange.min = 0;
|
|
43373
|
-
|
|
43374
|
-
// Max can be less than min if config.min is set but max left to autoscale. If that's the case there is
|
|
43375
|
-
// nothing to paint.
|
|
43376
|
-
if (this.dataRange.max > this.dataRange.min) {
|
|
43377
|
-
|
|
43378
|
-
let lastPixelEnd = -1;
|
|
43379
|
-
let lastY;
|
|
43380
|
-
const y0 = yScale(0);
|
|
43381
|
-
|
|
43382
|
-
for (let f of features) {
|
|
43383
|
-
|
|
43384
|
-
if (f.end < bpStart) continue
|
|
43385
|
-
if (f.start > bpEnd) break
|
|
43386
|
-
|
|
43387
|
-
const x = (f.start - bpStart) / bpPerPixel;
|
|
43388
|
-
if (isNaN(x)) continue
|
|
43389
|
-
|
|
43390
|
-
let y = yScale(f.value);
|
|
43391
|
-
|
|
43392
|
-
const rectEnd = (f.end - bpStart) / bpPerPixel;
|
|
43393
|
-
const width = rectEnd - x;
|
|
43394
|
-
|
|
43395
|
-
const color = options.alpha ? IGVColor.addAlpha(this.getColorForFeature(f), options.alpha) : this.getColorForFeature(f);
|
|
43396
|
-
|
|
43397
|
-
if (this.graphType === "line") {
|
|
43398
|
-
if (lastY !== undefined) {
|
|
43399
|
-
IGVGraphics.strokeLine(ctx, lastPixelEnd, lastY, x, y, {
|
|
43400
|
-
"fillStyle": color,
|
|
43401
|
-
"strokeStyle": color
|
|
43402
|
-
});
|
|
43403
|
-
}
|
|
43404
|
-
IGVGraphics.strokeLine(ctx, x, y, x + width, y, {"fillStyle": color, "strokeStyle": color});
|
|
43405
|
-
} else if (this.graphType === "points") {
|
|
43406
|
-
const pointSize = this.config.pointSize || 3;
|
|
43407
|
-
const px = x + width / 2;
|
|
43408
|
-
IGVGraphics.fillCircle(ctx, px, y, pointSize / 2, {"fillStyle": color, "strokeStyle": color});
|
|
43409
|
-
|
|
43410
|
-
if (f.value > this.dataRange.max) {
|
|
43411
|
-
IGVGraphics.fillCircle(ctx, px, pointSize / 2, pointSize / 2, 3, {fillStyle: this.overflowColor});
|
|
43412
|
-
} else if (f.value < this.dataRange.min) {
|
|
43413
|
-
IGVGraphics.fillCircle(ctx, px, pixelHeight - pointSize / 2, pointSize / 2, 3, {fillStyle: this.overflowColor});
|
|
43414
|
-
}
|
|
43415
|
-
|
|
43416
|
-
} else {
|
|
43417
|
-
// Default graph type (bar)
|
|
43418
|
-
const height = Math.min(pixelHeight, y - y0);
|
|
43419
|
-
IGVGraphics.fillRect(ctx, x, y0, width, height, {fillStyle: color});
|
|
43420
|
-
if (f.value > this.dataRange.max) {
|
|
43421
|
-
IGVGraphics.fillRect(ctx, x, 0, width, 3, {fillStyle: this.overflowColor});
|
|
43422
|
-
} else if (f.value < this.dataRange.min) {
|
|
43423
|
-
IGVGraphics.fillRect(ctx, x, pixelHeight - 3, width, 3, {fillStyle: this.overflowColor});
|
|
43424
|
-
}
|
|
43425
|
-
|
|
43426
|
-
}
|
|
43427
|
-
lastPixelEnd = x + width;
|
|
43428
|
-
lastY = y;
|
|
43429
|
-
}
|
|
43430
|
-
|
|
43431
|
-
// If the track includes negative values draw a baseline
|
|
43432
|
-
if (this.dataRange.min < 0) {
|
|
43433
|
-
const ratio = this.dataRange.max / (this.dataRange.max - this.dataRange.min);
|
|
43434
|
-
const basepx = this.flipAxis ? (1 - ratio) * options.pixelHeight : ratio * options.pixelHeight;
|
|
43435
|
-
IGVGraphics.strokeLine(ctx, 0, basepx, options.pixelWidth, basepx, {strokeStyle: this.baselineColor});
|
|
43436
|
-
}
|
|
43437
|
-
}
|
|
43438
|
-
}
|
|
43439
|
-
|
|
43440
|
-
// Draw guidelines
|
|
43441
|
-
if (this.config.hasOwnProperty('guideLines')) {
|
|
43442
|
-
for (let line of this.config.guideLines) {
|
|
43443
|
-
if (line.hasOwnProperty('color') && line.hasOwnProperty('y') && line.hasOwnProperty('dotted')) {
|
|
43444
|
-
let y = yScale(line.y);
|
|
43445
|
-
let props = {
|
|
43446
|
-
'strokeStyle': line['color'],
|
|
43447
|
-
'strokeWidth': 2
|
|
43448
|
-
};
|
|
43449
|
-
if (line['dotted']) IGVGraphics.dashedLine(options.context, 0, y, options.pixelWidth, y, 5, props);
|
|
43450
|
-
else IGVGraphics.strokeLine(options.context, 0, y, options.pixelWidth, y, props);
|
|
43451
|
-
}
|
|
43452
|
-
}
|
|
43453
|
-
}
|
|
43454
|
-
}
|
|
43455
|
-
|
|
43456
|
-
popupData(clickState, features) {
|
|
43457
|
-
|
|
43458
|
-
if (features === undefined) features = this.clickedFeatures(clickState);
|
|
43459
|
-
|
|
43460
|
-
if (features && features.length > 0) {
|
|
43461
|
-
|
|
43462
|
-
const genomicLocation = clickState.genomicLocation;
|
|
43463
|
-
const popupData = [];
|
|
43464
|
-
|
|
43465
|
-
// Sort features based on distance from click
|
|
43466
|
-
features.sort(function (a, b) {
|
|
43467
|
-
const distA = Math.abs((a.start + a.end) / 2 - genomicLocation);
|
|
43468
|
-
const distB = Math.abs((b.start + b.end) / 2 - genomicLocation);
|
|
43469
|
-
return distA - distB
|
|
43470
|
-
});
|
|
43471
|
-
|
|
43472
|
-
// Display closest 10
|
|
43473
|
-
const displayFeatures = features.length > 10 ? features.slice(0, 10) : features;
|
|
43474
|
-
|
|
43475
|
-
// Resort in ascending order
|
|
43476
|
-
displayFeatures.sort(function (a, b) {
|
|
43477
|
-
return a.start - b.start
|
|
43478
|
-
});
|
|
43479
|
-
|
|
43480
|
-
for (let selectedFeature of displayFeatures) {
|
|
43481
|
-
if (selectedFeature) {
|
|
43482
|
-
if (popupData.length > 0) {
|
|
43483
|
-
popupData.push('<hr/>');
|
|
43484
|
-
}
|
|
43485
|
-
let posString = (selectedFeature.end - selectedFeature.start) === 1 ?
|
|
43486
|
-
numberFormatter$1(Math.floor(selectedFeature.start) + 1)
|
|
43487
|
-
: numberFormatter$1(Math.floor(selectedFeature.start) + 1) + "-" + numberFormatter$1(Math.floor(selectedFeature.end));
|
|
43488
|
-
popupData.push({name: "Position:", value: posString});
|
|
43489
|
-
popupData.push({
|
|
43490
|
-
name: "Value: ",
|
|
43491
|
-
value: numberFormatter$1(selectedFeature.value.toFixed(4))
|
|
43492
|
-
});
|
|
43493
|
-
}
|
|
43494
|
-
}
|
|
43495
|
-
if (displayFeatures.length < features.length) {
|
|
43496
|
-
popupData.push("<hr/>...");
|
|
43497
|
-
}
|
|
43498
|
-
|
|
43499
|
-
return popupData
|
|
43500
|
-
|
|
43501
|
-
} else {
|
|
43502
|
-
return []
|
|
43503
|
-
}
|
|
43504
|
-
}
|
|
43505
|
-
|
|
43506
|
-
get supportsWholeGenome() {
|
|
43507
|
-
return !this.config.indexURL && this.config.supportsWholeGenome !== false
|
|
43508
|
-
}
|
|
43509
|
-
|
|
43510
|
-
/**
|
|
43511
|
-
* Return color for feature.
|
|
43512
|
-
* @param feature
|
|
43513
|
-
* @returns {string}
|
|
43514
|
-
*/
|
|
43515
|
-
|
|
43516
|
-
getColorForFeature(f) {
|
|
43517
|
-
let c = (f.value < 0 && this.altColor) ? this.altColor : this.color || DEFAULT_COLOR$1;
|
|
43518
|
-
return (typeof c === "function") ? c(f.value) : c
|
|
43519
|
-
}
|
|
43520
|
-
|
|
43521
|
-
/**
|
|
43522
|
-
* Called when the track is removed. Do any needed cleanup here
|
|
43523
|
-
*/
|
|
43524
|
-
dispose() {
|
|
43525
|
-
this.trackView = undefined;
|
|
43526
|
-
}
|
|
43527
|
-
|
|
43528
|
-
}
|
|
43529
|
-
|
|
43530
|
-
/**
|
|
43531
|
-
* Summarize wig data in bins of size "bpPerPixel" with the given window function.
|
|
43532
|
-
*
|
|
43533
|
-
* @param features wig (numeric) data -- features cannot overlap, and are in ascending order by start position
|
|
43534
|
-
* @param startBP bp start position for computing binned data
|
|
43535
|
-
* @param bpPerPixel bp per pixel (bin)
|
|
43536
|
-
* @param windowFunction mean, min, or max
|
|
43537
|
-
* @returns {*|*[]}
|
|
43538
|
-
*/
|
|
43539
|
-
function summarizeData(features, startBP, bpPerPixel, windowFunction = "mean") {
|
|
43540
|
-
|
|
43541
|
-
if (bpPerPixel <= 1 || !features || features.length === 0) {
|
|
43542
|
-
return features
|
|
43543
|
-
}
|
|
43544
|
-
|
|
43545
|
-
// Assume features are sorted by position. Wig features cannot overlap. Note, UCSC "reductionLevel" == bpPerPixel
|
|
43546
|
-
const chr = features[0].chr;
|
|
43547
|
-
const binSize = bpPerPixel;
|
|
43548
|
-
const summaryFeatures = [];
|
|
43549
|
-
|
|
43550
|
-
const finishBin = (bin) => {
|
|
43551
|
-
const start = startBP + bin.bin * binSize;
|
|
43552
|
-
const end = start + binSize;
|
|
43553
|
-
let value;
|
|
43554
|
-
switch (windowFunction) {
|
|
43555
|
-
case "mean":
|
|
43556
|
-
value = bin.sumData / bin.count;
|
|
43557
|
-
break
|
|
43558
|
-
case "max":
|
|
43559
|
-
value = bin.max;
|
|
43560
|
-
break
|
|
43561
|
-
case "min":
|
|
43562
|
-
value = bin.min;
|
|
43563
|
-
break
|
|
43564
|
-
default:
|
|
43565
|
-
throw Error(`Unknown window function: ${windowFunction}`)
|
|
43566
|
-
}
|
|
43567
|
-
const description = `${windowFunction} of ${bin.count} values`;
|
|
43568
|
-
summaryFeatures.push({chr, start, end, value, description});
|
|
43569
|
-
};
|
|
43570
|
-
|
|
43571
|
-
let currentBinData;
|
|
43572
|
-
for (let f of features) {
|
|
43573
|
-
|
|
43574
|
-
// Loop through bins this feature overlaps, updating the weighted sum for each bin or min/max,
|
|
43575
|
-
// depending on window function
|
|
43576
|
-
let startBin = Math.floor((f.start - startBP) / binSize);
|
|
43577
|
-
const endBin = Math.floor((f.end - startBP) / binSize);
|
|
43578
|
-
|
|
43579
|
-
if (currentBinData && startBin === currentBinData.bin) {
|
|
43580
|
-
currentBinData.add(f);
|
|
43581
|
-
startBin++;
|
|
43582
|
-
}
|
|
43583
|
-
|
|
43584
|
-
if (!currentBinData || endBin > currentBinData.bin) {
|
|
43585
|
-
|
|
43586
|
-
if(currentBinData) {
|
|
43587
|
-
finishBin(currentBinData);
|
|
43588
|
-
}
|
|
43589
|
-
|
|
43590
|
-
// Feature stretches across multiple bins.
|
|
43591
|
-
if (endBin > startBin) {
|
|
43592
|
-
const end = startBP + endBin * binSize;
|
|
43593
|
-
summaryFeatures.push({chr, start: f.start, end, value: f.value});
|
|
43594
|
-
}
|
|
43595
|
-
|
|
43596
|
-
currentBinData = new SummaryBinData(endBin, f);
|
|
43597
|
-
}
|
|
43598
|
-
|
|
43599
|
-
}
|
|
43600
|
-
if(currentBinData) {
|
|
43601
|
-
finishBin(currentBinData);
|
|
43602
|
-
}
|
|
43603
|
-
|
|
43604
|
-
// Consolidate
|
|
43605
|
-
const c = [];
|
|
43606
|
-
let lastFeature = summaryFeatures[0];
|
|
43607
|
-
for (let f of summaryFeatures) {
|
|
43608
|
-
if (lastFeature.value === f.value && f.start <= lastFeature.end) {
|
|
43609
|
-
lastFeature.end = f.end;
|
|
43610
|
-
} else {
|
|
43611
|
-
c.push(lastFeature);
|
|
43612
|
-
lastFeature = f;
|
|
43613
|
-
}
|
|
43614
|
-
}
|
|
43615
|
-
c.push(lastFeature);
|
|
43616
|
-
|
|
43617
|
-
return c
|
|
43618
|
-
|
|
43619
|
-
}
|
|
43620
|
-
|
|
43621
|
-
class SummaryBinData {
|
|
43622
|
-
constructor(bin, feature) {
|
|
43623
|
-
this.bin = bin;
|
|
43624
|
-
this.sumData = feature.value;
|
|
43625
|
-
this.count = 1;
|
|
43626
|
-
this.min = feature.value;
|
|
43627
|
-
this.max = feature.value;
|
|
43628
|
-
}
|
|
43629
|
-
|
|
43630
|
-
add(feature) {
|
|
43631
|
-
this.sumData += feature.value;
|
|
43632
|
-
this.max = Math.max(feature.value, this.max);
|
|
43633
|
-
this.min = Math.min(feature.value, this.min);
|
|
43634
|
-
this.count++;
|
|
43635
|
-
}
|
|
43636
|
-
|
|
43637
|
-
get mean() {
|
|
43638
|
-
return this.sumData / this.count
|
|
43639
|
-
}
|
|
43640
|
-
}
|
|
43641
|
-
|
|
43642
43641
|
/**
|
|
43643
43642
|
*
|
|
43644
43643
|
* @param cs - object containing
|
|
@@ -48553,7 +48552,7 @@ class AlignmentContainer {
|
|
|
48553
48552
|
allAlignments() {
|
|
48554
48553
|
if (this.alignments) {
|
|
48555
48554
|
return this.alignments
|
|
48556
|
-
} else {
|
|
48555
|
+
} else if (this.packedGroups) {
|
|
48557
48556
|
const all = Array.from(this.packedGroups.values()).flatMap(group => group.rows.flatMap(row => row.alignments));
|
|
48558
48557
|
if (this.#unpacked && this.#unpacked.length > 0) {
|
|
48559
48558
|
for (let a of this.#unpacked) {
|
|
@@ -48561,6 +48560,8 @@ class AlignmentContainer {
|
|
|
48561
48560
|
}
|
|
48562
48561
|
}
|
|
48563
48562
|
return all
|
|
48563
|
+
} else {
|
|
48564
|
+
return []
|
|
48564
48565
|
}
|
|
48565
48566
|
}
|
|
48566
48567
|
|
|
@@ -48569,9 +48570,10 @@ class AlignmentContainer {
|
|
|
48569
48570
|
}
|
|
48570
48571
|
|
|
48571
48572
|
sortRows(options) {
|
|
48572
|
-
|
|
48573
|
-
|
|
48574
|
-
|
|
48573
|
+
if(this.packedGroups) {
|
|
48574
|
+
for (let group of this.packedGroups.values()) {
|
|
48575
|
+
group.sortRows(options, this);
|
|
48576
|
+
}
|
|
48575
48577
|
}
|
|
48576
48578
|
}
|
|
48577
48579
|
}
|
|
@@ -57361,23 +57363,24 @@ class AlignmentTrack extends TrackBase {
|
|
|
57361
57363
|
const y = clickState.y;
|
|
57362
57364
|
const offsetY = y - this.top;
|
|
57363
57365
|
const genomicLocation = clickState.genomicLocation;
|
|
57364
|
-
|
|
57365
|
-
|
|
57366
|
-
|
|
57367
|
-
|
|
57368
|
-
|
|
57369
|
-
|
|
57370
|
-
|
|
57371
|
-
|
|
57372
|
-
|
|
57373
|
-
|
|
57374
|
-
|
|
57375
|
-
|
|
57376
|
-
|
|
57377
|
-
|
|
57378
|
-
|
|
57379
|
-
|
|
57380
|
-
|
|
57366
|
+
|
|
57367
|
+
if(features.packedGroups) {
|
|
57368
|
+
let minGroupY = Number.MAX_VALUE;
|
|
57369
|
+
for (let group of features.packedGroups.values()) {
|
|
57370
|
+
minGroupY = Math.min(minGroupY, group.pixelTop);
|
|
57371
|
+
if (offsetY > group.pixelTop && offsetY <= group.pixelBottom) {
|
|
57372
|
+
|
|
57373
|
+
const alignmentRowHeight = this.displayMode === "SQUISHED" ?
|
|
57374
|
+
this.squishedRowHeight :
|
|
57375
|
+
this.alignmentRowHeight;
|
|
57376
|
+
|
|
57377
|
+
let packedAlignmentsIndex = Math.floor((offsetY - group.pixelTop) / alignmentRowHeight);
|
|
57378
|
+
|
|
57379
|
+
if (packedAlignmentsIndex >= 0 && packedAlignmentsIndex < group.length) {
|
|
57380
|
+
const alignmentRow = group.rows[packedAlignmentsIndex];
|
|
57381
|
+
const clicked = alignmentRow.alignments.filter(alignment => alignment.containsLocation(genomicLocation, this.showSoftClips));
|
|
57382
|
+
if (clicked.length > 0) return clicked[0]
|
|
57383
|
+
}
|
|
57381
57384
|
}
|
|
57382
57385
|
}
|
|
57383
57386
|
}
|
|
@@ -70512,7 +70515,7 @@ function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, v
|
|
|
70512
70515
|
})
|
|
70513
70516
|
}
|
|
70514
70517
|
|
|
70515
|
-
const _version = "3.0.
|
|
70518
|
+
const _version = "3.0.3";
|
|
70516
70519
|
function version() {
|
|
70517
70520
|
return _version
|
|
70518
70521
|
}
|
|
@@ -71983,16 +71986,17 @@ class ROIMenu {
|
|
|
71983
71986
|
|
|
71984
71987
|
}
|
|
71985
71988
|
|
|
71986
|
-
async present(feature,
|
|
71987
|
-
const menuItems = this.menuItems(feature,
|
|
71989
|
+
async present(feature, roiSet, event, roiManager, columnContainer, regionElement) {
|
|
71990
|
+
const menuItems = this.menuItems(feature, roiSet, event, roiManager, columnContainer, regionElement);
|
|
71988
71991
|
this.browser.menuPopup.presentTrackContextMenu(event, menuItems);
|
|
71989
71992
|
}
|
|
71990
71993
|
|
|
71991
|
-
menuItems(feature,
|
|
71994
|
+
menuItems(feature, roiSet, event, roiManager, columnContainer, regionElement) {
|
|
71995
|
+
const items = feature.name ? [`<b>${feature.name}</b><br/>`] : [];
|
|
71996
|
+
if ('name' in roiSet) items.push(`<b>ROI Set: ${roiSet.name}</b>`);
|
|
71997
|
+
if (items.length > 0) items.push(`<hr/>`);
|
|
71992
71998
|
|
|
71993
|
-
|
|
71994
|
-
|
|
71995
|
-
if (isUserDefined) {
|
|
71999
|
+
if (roiSet.isUserDefined) {
|
|
71996
72000
|
items.push(
|
|
71997
72001
|
{
|
|
71998
72002
|
label: 'Set description ...',
|
|
@@ -72056,7 +72060,7 @@ class ROIMenu {
|
|
|
72056
72060
|
}
|
|
72057
72061
|
|
|
72058
72062
|
|
|
72059
|
-
if (isUserDefined) {
|
|
72063
|
+
if (roiSet.isUserDefined) {
|
|
72060
72064
|
items.push(
|
|
72061
72065
|
'<hr/>',
|
|
72062
72066
|
{
|
|
@@ -72341,13 +72345,17 @@ class ROIManager {
|
|
|
72341
72345
|
const [rectA, rectB] = tracks
|
|
72342
72346
|
.map(track => track.trackView.viewports[0].$viewport.get(0))
|
|
72343
72347
|
.map(element => getElementVerticalDimension(element));
|
|
72344
|
-
|
|
72348
|
+
|
|
72349
|
+
//Covers cases in which ruler and/or ideogram are hidden
|
|
72350
|
+
const heightA = rectA ? rectA.height : 0;
|
|
72351
|
+
const heightB = rectB ? rectB.height : 0;
|
|
72352
|
+
|
|
72345
72353
|
const elements = browser.columnContainer.querySelectorAll('.igv-roi-region');
|
|
72346
72354
|
|
|
72347
72355
|
const fudge = -0.5;
|
|
72348
72356
|
if (elements) {
|
|
72349
72357
|
for (const element of elements) {
|
|
72350
|
-
element.style.marginTop = `${
|
|
72358
|
+
element.style.marginTop = `${heightA + heightB + fudge}px`;
|
|
72351
72359
|
}
|
|
72352
72360
|
|
|
72353
72361
|
}
|
|
@@ -72515,7 +72523,6 @@ class ROIManager {
|
|
|
72515
72523
|
if (features) {
|
|
72516
72524
|
|
|
72517
72525
|
for (let feature of features) {
|
|
72518
|
-
|
|
72519
72526
|
const regionKey = createRegionKey(chr, feature.start, feature.end);
|
|
72520
72527
|
|
|
72521
72528
|
const {
|
|
@@ -72560,8 +72567,7 @@ class ROIManager {
|
|
|
72560
72567
|
event.stopPropagation();
|
|
72561
72568
|
|
|
72562
72569
|
translateMouseCoordinates(event, columnContainer);
|
|
72563
|
-
|
|
72564
|
-
this.roiMenu.present(feature, isUserDefined, event, this, columnContainer, regionElement);
|
|
72570
|
+
this.roiMenu.present(feature, roiSet, event, this, columnContainer, regionElement);
|
|
72565
72571
|
});
|
|
72566
72572
|
|
|
72567
72573
|
|
|
@@ -73730,7 +73736,7 @@ function generateGenomeID(config) {
|
|
|
73730
73736
|
}
|
|
73731
73737
|
}
|
|
73732
73738
|
|
|
73733
|
-
var igvCss = '.igv-ui-dropdown {\n cursor: default;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n background-color: white;\n}\n.igv-ui-dropdown > div {\n overflow-y: auto;\n overflow-x: hidden;\n background-color: white;\n}\n.igv-ui-dropdown > div > div {\n padding: 4px;\n width: 100%;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: 1px;\n background-color: white;\n}\n.igv-ui-dropdown > div > div:last-child {\n border-bottom-color: transparent;\n border-bottom-width: 0;\n}\n.igv-ui-dropdown > div > div:hover {\n cursor: pointer;\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.igv-ui-popover {\n cursor: default;\n position: absolute;\n z-index: 2048;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n background-color: white;\n}\n.igv-ui-popover > div:first-child {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-width: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-popover > div:first-child > div:first-child {\n margin-left: 4px;\n}\n.igv-ui-popover > div:first-child > div:last-child {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-popover > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-popover > div:last-child {\n user-select: text;\n overflow-y: auto;\n overflow-x: hidden;\n max-height: 400px;\n max-width: 800px;\n background-color: white;\n border-bottom-width: 0;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-ui-popover > div:last-child > div {\n margin-left: 4px;\n margin-right: 4px;\n min-width: 220px;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.igv-ui-popover > div:last-child > div > span {\n font-weight: bolder;\n}\n.igv-ui-popover > div:last-child hr {\n width: 100%;\n}\n\n.igv-ui-alert-dialog-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n top: 50%;\n left: 50%;\n width: 400px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n outline: none;\n font-family: \"Open Sans\", sans-serif;\n font-size: 15px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-ui-alert-dialog-container > div:first-child {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-alert-dialog-container > div:first-child div:first-child {\n padding-left: 8px;\n}\n.igv-ui-alert-dialog-container .igv-ui-alert-dialog-body {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n color: #373737;\n width: 100%;\n height: calc(100% - 24px - 64px);\n overflow-y: scroll;\n}\n.igv-ui-alert-dialog-container .igv-ui-alert-dialog-body .igv-ui-alert-dialog-body-copy {\n margin: 16px;\n width: auto;\n height: auto;\n overflow-wrap: break-word;\n word-break: break-word;\n background-color: white;\n border: unset;\n}\n.igv-ui-alert-dialog-container > div:last-child {\n width: 100%;\n margin-bottom: 10px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-ui-alert-dialog-container > div:last-child div {\n margin: unset;\n width: 40px;\n height: 30px;\n line-height: 30px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n border-color: #2B81AF;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-ui-alert-dialog-container > div:last-child div:hover {\n cursor: pointer;\n border-color: #25597f;\n background-color: #25597f;\n}\n\n.igv-ui-color-swatch {\n position: relative;\n box-sizing: content-box;\n display: flex;\n flex-flow: row;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n width: 32px;\n height: 32px;\n border-style: solid;\n border-width: 2px;\n border-color: white;\n border-radius: 4px;\n}\n\n.igv-ui-color-swatch:hover {\n border-color: dimgray;\n}\n\n.igv-ui-colorpicker-menu-close-button {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 32px;\n margin-top: 4px;\n margin-bottom: 4px;\n padding-right: 8px;\n}\n.igv-ui-colorpicker-menu-close-button i.fa {\n display: block;\n margin-left: 4px;\n margin-right: 4px;\n color: #5f5f5f;\n}\n.igv-ui-colorpicker-menu-close-button i.fa:hover,\n.igv-ui-colorpicker-menu-close-button i.fa:focus,\n.igv-ui-colorpicker-menu-close-button i.fa:active {\n cursor: pointer;\n color: #0f0f0f;\n}\n\n.igv-ui-generic-dialog-container {\n box-sizing: content-box;\n position: fixed;\n top: 0;\n left: 0;\n width: 300px;\n height: fit-content;\n padding-bottom: 16px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input > div {\n width: fit-content;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input[type=range] {\n width: 70%;\n -webkit-appearance: none;\n background: linear-gradient(90deg, white, black);\n outline: none;\n margin: 0;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input output {\n display: block;\n height: 100%;\n width: 20%;\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n padding-top: 16px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div {\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n\n.igv-ui-generic-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-container > div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-ui-generic-container > div:first-child > div {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-ui-dialog {\n z-index: 2048;\n position: fixed;\n width: fit-content;\n height: fit-content;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n background-color: white;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n}\n.igv-ui-dialog .igv-ui-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-dialog .igv-ui-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-dialog .igv-ui-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-dialog .igv-ui-dialog-one-liner {\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin: 8px;\n overflow-wrap: break-word;\n background-color: white;\n font-weight: bold;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel {\n width: 100%;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div {\n margin: 16px;\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child {\n background-color: #5ea4e0;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child {\n background-color: #c4c4c4;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-ui-dialog .igv-ui-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-dialog .igv-ui-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-ui-dialog .igv-ui-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-ui-panel, .igv-ui-panel-row, .igv-ui-panel-column {\n z-index: 2048;\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-ui-panel-column {\n display: flex;\n flex-direction: column;\n}\n\n.igv-ui-panel-row {\n display: flex;\n flex-direction: row;\n}\n\n.igv-ui-textbox {\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-ui-table {\n background-color: white;\n}\n\n.igv-ui-table thead {\n position: sticky;\n top: 0;\n}\n\n.igv-ui-table th {\n text-align: left;\n}\n\n.igv-ui-table td {\n padding-right: 20px;\n}\n\n.igv-ui-table tr:hover {\n background-color: lightblue;\n}\n\n.igv-ui-center-fixed {\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n}\n\n.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3;\n}\n.igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 240px;\n height: 22px;\n line-height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none;\n}\n.igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n position: relative;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-hidden {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 20px;\n width: 20px;\n margin-left: unset;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 20px;\n width: 20px;\n margin-left: 4px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 20px;\n width: 20px;\n margin-left: unset;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 20px;\n width: 20px;\n margin-left: 4px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none;\n}\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px;\n}\n\n.igv-navbar-button:hover {\n cursor: pointer;\n}\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373;\n}\n\n.igv-navbar-icon-button {\n cursor: pointer;\n position: relative;\n width: 24px;\n height: 24px;\n margin-left: 4px;\n margin-right: 4px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-icon-button > div:first-child {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: -18px;\n width: 24px;\n height: 24px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-icon-button > div:last-child {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 18px;\n width: 24px;\n height: 24px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n.igv-navbar-text-button {\n cursor: pointer;\n position: relative;\n margin-left: 2px;\n margin-right: 2px;\n border: none;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.igv-navbar-text-button > div:nth-child(2) {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 0;\n width: 38px;\n height: 18px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-text-button > div:nth-child(3) {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 42px;\n width: 38px;\n height: 18px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n#igv-text-button-label {\n text-anchor: middle;\n dominant-baseline: middle;\n}\n\n.igv-navbar-text-button-svg-inactive rect {\n stroke: #737373;\n fill: white;\n}\n.igv-navbar-text-button-svg-inactive text {\n fill: #737373;\n}\n.igv-navbar-text-button-svg-inactive tspan {\n dominant-baseline: middle;\n}\n\n.igv-navbar-text-button-svg-hover rect {\n stroke: #737373;\n fill: #737373;\n}\n.igv-navbar-text-button-svg-hover text {\n fill: white;\n}\n.igv-navbar-text-button-svg-hover tspan {\n dominant-baseline: middle;\n}\n\n#igv-save-svg-group rect {\n stroke: #737373;\n fill: white;\n}\n#igv-save-svg-group text {\n fill: #737373;\n}\n\n#igv-save-svg-group:hover rect {\n stroke: #737373;\n fill: #737373;\n}\n#igv-save-svg-group:hover text {\n fill: white;\n}\n\n#igv-save-png-group rect {\n stroke: #737373;\n fill: white;\n}\n#igv-save-png-group text {\n fill: #737373;\n}\n\n#igv-save-png-group:hover rect {\n stroke: #737373;\n fill: #737373;\n}\n#igv-save-png-group:hover text {\n fill: white;\n}\n\n.igv-zoom-in-notice-container {\n z-index: 256;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white;\n}\n.igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f;\n}\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%;\n}\n.igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64;\n}\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373;\n}\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 12px;\n height: 12px;\n color: #666666;\n background-color: white;\n z-index: 1000;\n}\n.igv-multi-locus-close-button > svg {\n vertical-align: top;\n}\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343;\n}\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 12px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-multi-locus-ruler-label > div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n color: rgb(16, 16, 16);\n background-color: white;\n}\n.igv-multi-locus-ruler-label > div {\n cursor: pointer;\n}\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px;\n}\n.igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n}\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 26px;\n bottom: 0;\n left: 0;\n width: 0;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25);\n}\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737;\n}\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 50%;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer;\n}\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8;\n}\n\n.igv-track-label-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-top: 4px;\n}\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin;\n}\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51);\n}\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0);\n}\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 32;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76);\n}\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 32;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n z-index: 512;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left;\n}\n.igv-menu-popup > div:not(:first-child) {\n width: 100%;\n}\n.igv-menu-popup > div:not(:first-child) > div {\n background: white;\n}\n.igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px;\n}\n.igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef;\n}\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-bottom: 1px;\n padding-top: 1px;\n}\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444;\n}\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n margin-right: 4px;\n background-color: transparent;\n}\n.igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px;\n}\n.igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px;\n}\n.igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: rgb(255, 255, 255);\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite;\n}\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.igv-roi-menu {\n position: absolute;\n z-index: 512;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background-color: white;\n width: 192px;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu > div:first-child {\n height: 24px;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-roi-menu > div:first-child > div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-roi-menu > div:first-child > div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-menu > div:last-child {\n background-color: white;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n text-align: start;\n vertical-align: middle;\n}\n.igv-roi-menu > div:last-child > div {\n height: 24px;\n padding-left: 4px;\n border-bottom-style: solid;\n border-bottom-width: thin;\n border-bottom-color: #7f7f7f;\n}\n.igv-roi-menu > div:last-child > div:not(:first-child):hover {\n cursor: pointer;\n background-color: rgba(127, 127, 127, 0.1);\n}\n.igv-roi-menu > div:last-child div:first-child {\n font-style: italic;\n text-align: center;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-menu > div:last-child > div:last-child {\n border-bottom-width: 0;\n border-bottom-color: transparent;\n}\n\n.igv-roi-placeholder {\n font-style: normal;\n color: rgba(75, 75, 75, 0.6);\n}\n\n.igv-roi-table {\n position: absolute;\n z-index: 1024;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n resize: both;\n overflow: hidden;\n width: min-content;\n max-width: 1600px;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n cursor: default;\n}\n.igv-roi-table > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table > div:first-child > div:first-child {\n text-align: center;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n margin-left: 4px;\n margin-right: 4px;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table > .igv-roi-table-description {\n padding: 4px;\n margin-left: 4px;\n word-break: break-all;\n overflow-y: auto;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-goto-explainer {\n margin-top: 5px;\n margin-left: 4px;\n color: #7F7F7F;\n font-style: italic;\n height: 24px;\n border-top: solid lightgray;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: left;\n margin-left: 4px;\n height: 24px;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right-color: #7f7f7f;\n border-right-style: solid;\n border-right-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:last-child {\n border-right: unset;\n}\n.igv-roi-table > .igv-roi-table-row-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n overflow: auto;\n height: 360px;\n flex: 1 1 auto;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: left;\n margin-left: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right-color: transparent;\n border-right-style: solid;\n border-right-width: thin;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:last-child {\n border-right: unset;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table > div:last-child {\n min-height: 32px;\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-row-selected {\n background-color: rgba(0, 0, 0, 0.125);\n}\n\n.igv-roi-table-button {\n cursor: pointer;\n height: 20px;\n user-select: none;\n line-height: 20px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 13px;\n font-weight: 400;\n color: black;\n padding-left: 6px;\n padding-right: 6px;\n background-color: rgb(239, 239, 239);\n border-color: black;\n border-style: solid;\n border-width: thin;\n border-radius: 3px;\n}\n\n.igv-roi-table-button:hover {\n font-weight: 400;\n background-color: rgba(0, 0, 0, 0.13);\n}\n\n.igv-roi-region {\n z-index: 64;\n position: absolute;\n top: 0;\n bottom: 0;\n pointer-events: none;\n overflow: visible;\n margin-top: 66px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-region > div {\n position: relative;\n width: 100%;\n height: 8px;\n pointer-events: auto;\n}\n\n.igv-roi-menu-row {\n height: 24px;\n padding-left: 8px;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n background-color: white;\n}\n\n.igv-roi-menu-row-edit-description {\n width: -webkit-fill-available;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n background-color: white;\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-menu-row-edit-description > label {\n margin-left: 2px;\n margin-bottom: 0;\n display: block;\n width: -webkit-fill-available;\n}\n.igv-roi-menu-row-edit-description > input {\n display: block;\n margin-left: 2px;\n margin-right: 2px;\n margin-bottom: 1px;\n width: -webkit-fill-available;\n}\n\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n min-height: 160px;\n}\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n line-height: 1;\n overflow-x: hidden;\n overflow-y: hidden;\n}\n\n.igv-viewport-content {\n position: relative;\n width: 100%;\n}\n.igv-viewport-content > canvas {\n position: relative;\n display: block;\n}\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%;\n}\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453;\n}\n\n.igv-axis-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px;\n}\n.igv-axis-column > div {\n position: relative;\n margin-top: 5px;\n width: 100%;\n}\n.igv-axis-column > div > div {\n z-index: 512;\n position: absolute;\n top: 8px;\n left: 8px;\n width: fit-content;\n height: fit-content;\n background-color: transparent;\n display: grid;\n align-items: start;\n justify-items: center;\n}\n.igv-axis-column > div > div > input {\n display: block;\n margin: unset;\n cursor: pointer;\n}\n\n.igv-column {\n position: relative;\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-sample-info-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-sample-name-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-scrollbar-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px;\n}\n.igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px;\n}\n.igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4;\n}\n\n.igv-track-drag-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white;\n}\n.igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.igv-track-drag-column .igv-track-drag-handle-color {\n background-color: #c4c4c4;\n}\n.igv-track-drag-column .igv-track-drag-handle-hover-color {\n background-color: #787878;\n}\n.igv-track-drag-column .igv-track-drag-handle-selected-color {\n background-color: #0963fa;\n}\n.igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n}\n\n.igv-gear-menu-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px;\n}\n.igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white;\n}\n.igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F;\n}\n.igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444;\n}\n\n/*# sourceMappingURL=igv.css.map */\n';
|
|
73739
|
+
var igvCss = '.igv-ui-dropdown {\n cursor: default;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n background-color: white;\n}\n.igv-ui-dropdown > div {\n overflow-y: auto;\n overflow-x: hidden;\n background-color: white;\n}\n.igv-ui-dropdown > div > div {\n padding: 4px;\n width: 100%;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: 1px;\n background-color: white;\n}\n.igv-ui-dropdown > div > div:last-child {\n border-bottom-color: transparent;\n border-bottom-width: 0;\n}\n.igv-ui-dropdown > div > div:hover {\n cursor: pointer;\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.igv-ui-popover {\n cursor: default;\n position: absolute;\n z-index: 2048;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: 1px;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n background-color: white;\n}\n.igv-ui-popover > div:first-child {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-width: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-popover > div:first-child > div:first-child {\n margin-left: 4px;\n}\n.igv-ui-popover > div:first-child > div:last-child {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-popover > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-popover > div:last-child {\n user-select: text;\n overflow-y: auto;\n overflow-x: hidden;\n max-height: 400px;\n max-width: 800px;\n background-color: white;\n border-bottom-width: 0;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-ui-popover > div:last-child > div {\n margin-left: 4px;\n margin-right: 4px;\n min-width: 220px;\n overflow-x: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.igv-ui-popover > div:last-child > div > span {\n font-weight: bolder;\n}\n.igv-ui-popover > div:last-child hr {\n width: 100%;\n}\n\n.igv-ui-alert-dialog-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n top: 50%;\n left: 50%;\n width: 400px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n outline: none;\n font-family: \"Open Sans\", sans-serif;\n font-size: 15px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-ui-alert-dialog-container > div:first-child {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-alert-dialog-container > div:first-child div:first-child {\n padding-left: 8px;\n}\n.igv-ui-alert-dialog-container .igv-ui-alert-dialog-body {\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n color: #373737;\n width: 100%;\n height: calc(100% - 24px - 64px);\n overflow-y: scroll;\n}\n.igv-ui-alert-dialog-container .igv-ui-alert-dialog-body .igv-ui-alert-dialog-body-copy {\n margin: 16px;\n width: auto;\n height: auto;\n overflow-wrap: break-word;\n word-break: break-word;\n background-color: white;\n border: unset;\n}\n.igv-ui-alert-dialog-container > div:last-child {\n width: 100%;\n margin-bottom: 10px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-ui-alert-dialog-container > div:last-child div {\n margin: unset;\n width: 40px;\n height: 30px;\n line-height: 30px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n border-color: #2B81AF;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-ui-alert-dialog-container > div:last-child div:hover {\n cursor: pointer;\n border-color: #25597f;\n background-color: #25597f;\n}\n\n.igv-ui-color-swatch {\n position: relative;\n box-sizing: content-box;\n display: flex;\n flex-flow: row;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n width: 32px;\n height: 32px;\n border-style: solid;\n border-width: 2px;\n border-color: white;\n border-radius: 4px;\n}\n\n.igv-ui-color-swatch:hover {\n border-color: dimgray;\n}\n\n.igv-ui-colorpicker-menu-close-button {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 32px;\n margin-top: 4px;\n margin-bottom: 4px;\n padding-right: 8px;\n}\n.igv-ui-colorpicker-menu-close-button i.fa {\n display: block;\n margin-left: 4px;\n margin-right: 4px;\n color: #5f5f5f;\n}\n.igv-ui-colorpicker-menu-close-button i.fa:hover,\n.igv-ui-colorpicker-menu-close-button i.fa:focus,\n.igv-ui-colorpicker-menu-close-button i.fa:active {\n cursor: pointer;\n color: #0f0f0f;\n}\n\n.igv-ui-generic-dialog-container {\n box-sizing: content-box;\n position: fixed;\n top: 0;\n left: 0;\n width: 300px;\n height: fit-content;\n padding-bottom: 16px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input > div {\n width: fit-content;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input input[type=range] {\n width: 70%;\n -webkit-appearance: none;\n background: linear-gradient(90deg, white, black);\n outline: none;\n margin: 0;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-input output {\n display: block;\n height: 100%;\n width: 20%;\n font-size: 16px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n padding-top: 16px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div {\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-ui-generic-dialog-container .igv-ui-generic-dialog-ok-cancel > div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n\n.igv-ui-generic-container {\n box-sizing: content-box;\n position: absolute;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ui-generic-container > div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-ui-generic-container > div:first-child > div {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-ui-dialog {\n z-index: 2048;\n position: fixed;\n width: fit-content;\n height: fit-content;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n background-color: white;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n}\n.igv-ui-dialog .igv-ui-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-ui-dialog .igv-ui-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-ui-dialog .igv-ui-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-ui-dialog .igv-ui-dialog-one-liner {\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin: 8px;\n overflow-wrap: break-word;\n background-color: white;\n font-weight: bold;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel {\n width: 100%;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div {\n margin: 16px;\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child {\n background-color: #5ea4e0;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child {\n background-color: #c4c4c4;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-ui-dialog .igv-ui-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-ui-dialog .igv-ui-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-ui-dialog .igv-ui-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-ui-dialog .igv-ui-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-ui-panel, .igv-ui-panel-row, .igv-ui-panel-column {\n z-index: 2048;\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-ui-panel-column {\n display: flex;\n flex-direction: column;\n}\n\n.igv-ui-panel-row {\n display: flex;\n flex-direction: row;\n}\n\n.igv-ui-textbox {\n background-color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-ui-table {\n background-color: white;\n}\n\n.igv-ui-table thead {\n position: sticky;\n top: 0;\n}\n\n.igv-ui-table th {\n text-align: left;\n}\n\n.igv-ui-table td {\n padding-right: 20px;\n}\n\n.igv-ui-table tr:hover {\n background-color: lightblue;\n}\n\n.igv-ui-center-fixed {\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n}\n\n.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3;\n}\n.igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 240px;\n height: 22px;\n line-height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none;\n}\n.igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n position: relative;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-hidden {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 20px;\n width: 20px;\n margin-left: unset;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 20px;\n width: 20px;\n margin-left: 4px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 20px;\n width: 20px;\n margin-left: unset;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 20px;\n width: 20px;\n margin-left: 4px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none;\n}\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px;\n}\n\n.igv-navbar-button:hover {\n cursor: pointer;\n}\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373;\n}\n\n.igv-navbar-icon-button {\n cursor: pointer;\n position: relative;\n width: 24px;\n height: 24px;\n margin-left: 4px;\n margin-right: 4px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-icon-button > div:first-child {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: -18px;\n width: 24px;\n height: 24px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-icon-button > div:last-child {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 18px;\n width: 24px;\n height: 24px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n.igv-navbar-text-button {\n cursor: pointer;\n position: relative;\n margin-left: 2px;\n margin-right: 2px;\n border: none;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.igv-navbar-text-button > div:nth-child(2) {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 0;\n width: 38px;\n height: 18px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n.igv-navbar-text-button > div:nth-child(3) {\n z-index: 512;\n position: absolute;\n top: 36px;\n left: 42px;\n width: 38px;\n height: 18px;\n border: none;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n#igv-text-button-label {\n text-anchor: middle;\n dominant-baseline: middle;\n}\n\n.igv-navbar-text-button-svg-inactive rect {\n stroke: #737373;\n fill: white;\n}\n.igv-navbar-text-button-svg-inactive text {\n fill: #737373;\n}\n.igv-navbar-text-button-svg-inactive tspan {\n dominant-baseline: middle;\n}\n\n.igv-navbar-text-button-svg-hover rect {\n stroke: #737373;\n fill: #737373;\n}\n.igv-navbar-text-button-svg-hover text {\n fill: white;\n}\n.igv-navbar-text-button-svg-hover tspan {\n dominant-baseline: middle;\n}\n\n#igv-save-svg-group rect {\n stroke: #737373;\n fill: white;\n}\n#igv-save-svg-group text {\n fill: #737373;\n}\n\n#igv-save-svg-group:hover rect {\n stroke: #737373;\n fill: #737373;\n}\n#igv-save-svg-group:hover text {\n fill: white;\n}\n\n#igv-save-png-group rect {\n stroke: #737373;\n fill: white;\n}\n#igv-save-png-group text {\n fill: #737373;\n}\n\n#igv-save-png-group:hover rect {\n stroke: #737373;\n fill: #737373;\n}\n#igv-save-png-group:hover text {\n fill: white;\n}\n\n.igv-zoom-in-notice-container {\n z-index: 256;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white;\n}\n.igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f;\n}\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%;\n}\n.igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64;\n}\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373;\n}\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 12px;\n height: 12px;\n color: #666666;\n background-color: white;\n z-index: 1000;\n}\n.igv-multi-locus-close-button > svg {\n vertical-align: top;\n}\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343;\n}\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 12px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-multi-locus-ruler-label > div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n color: rgb(16, 16, 16);\n background-color: white;\n}\n.igv-multi-locus-ruler-label > div {\n cursor: pointer;\n}\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px;\n}\n.igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n}\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 26px;\n bottom: 0;\n left: 0;\n width: 0;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25);\n}\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737;\n}\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 50%;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer;\n}\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8;\n}\n\n.igv-track-label-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-top: 4px;\n}\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin;\n}\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51);\n}\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0);\n}\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 32;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76);\n}\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 32;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n max-width: 400px;\n z-index: 512;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left;\n}\n.igv-menu-popup > div:not(:first-child) {\n width: 100%;\n}\n.igv-menu-popup > div:not(:first-child) > div {\n background: white;\n}\n.igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px;\n}\n.igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef;\n}\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-bottom: 1px;\n padding-top: 1px;\n}\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444;\n}\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n margin-right: 4px;\n background-color: transparent;\n}\n.igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px;\n}\n.igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px;\n}\n.igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: rgb(255, 255, 255);\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite;\n}\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.igv-roi-menu {\n position: absolute;\n z-index: 512;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background-color: white;\n width: 192px;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu > div:first-child {\n height: 24px;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-roi-menu > div:first-child > div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-roi-menu > div:first-child > div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-menu > div:last-child {\n background-color: white;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n text-align: start;\n vertical-align: middle;\n}\n.igv-roi-menu > div:last-child > div {\n height: 24px;\n padding-left: 4px;\n border-bottom-style: solid;\n border-bottom-width: thin;\n border-bottom-color: #7f7f7f;\n}\n.igv-roi-menu > div:last-child > div:not(:first-child):hover {\n cursor: pointer;\n background-color: rgba(127, 127, 127, 0.1);\n}\n.igv-roi-menu > div:last-child div:first-child {\n font-style: italic;\n text-align: center;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-menu > div:last-child > div:last-child {\n border-bottom-width: 0;\n border-bottom-color: transparent;\n}\n\n.igv-roi-placeholder {\n font-style: normal;\n color: rgba(75, 75, 75, 0.6);\n}\n\n.igv-roi-table {\n position: absolute;\n z-index: 1024;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n resize: both;\n overflow: hidden;\n width: min-content;\n max-width: 1600px;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n cursor: default;\n}\n.igv-roi-table > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table > div:first-child > div:first-child {\n text-align: center;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n margin-left: 4px;\n margin-right: 4px;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table > .igv-roi-table-description {\n padding: 4px;\n margin-left: 4px;\n word-break: break-all;\n overflow-y: auto;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-goto-explainer {\n margin-top: 5px;\n margin-left: 4px;\n color: #7F7F7F;\n font-style: italic;\n height: 24px;\n border-top: solid lightgray;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: left;\n margin-left: 4px;\n height: 24px;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right-color: #7f7f7f;\n border-right-style: solid;\n border-right-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:last-child {\n border-right: unset;\n}\n.igv-roi-table > .igv-roi-table-row-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n overflow: auto;\n height: 360px;\n flex: 1 1 auto;\n background-color: transparent;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: left;\n margin-left: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right-color: transparent;\n border-right-style: solid;\n border-right-width: thin;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:last-child {\n border-right: unset;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table > div:last-child {\n min-height: 32px;\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-row-selected {\n background-color: rgba(0, 0, 0, 0.125);\n}\n\n.igv-roi-table-button {\n cursor: pointer;\n height: 20px;\n user-select: none;\n line-height: 20px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 13px;\n font-weight: 400;\n color: black;\n padding-left: 6px;\n padding-right: 6px;\n background-color: rgb(239, 239, 239);\n border-color: black;\n border-style: solid;\n border-width: thin;\n border-radius: 3px;\n}\n\n.igv-roi-table-button:hover {\n font-weight: 400;\n background-color: rgba(0, 0, 0, 0.13);\n}\n\n.igv-roi-region {\n z-index: 64;\n position: absolute;\n top: 0;\n bottom: 0;\n pointer-events: none;\n overflow: visible;\n margin-top: 66px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-region > div {\n position: relative;\n width: 100%;\n height: 8px;\n pointer-events: auto;\n}\n\n.igv-roi-menu-row {\n height: 24px;\n padding-left: 8px;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n background-color: white;\n}\n\n.igv-roi-menu-row-edit-description {\n width: -webkit-fill-available;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n background-color: white;\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-menu-row-edit-description > label {\n margin-left: 2px;\n margin-bottom: 0;\n display: block;\n width: -webkit-fill-available;\n}\n.igv-roi-menu-row-edit-description > input {\n display: block;\n margin-left: 2px;\n margin-right: 2px;\n margin-bottom: 1px;\n width: -webkit-fill-available;\n}\n\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n min-height: 160px;\n}\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n line-height: 1;\n overflow-x: hidden;\n overflow-y: hidden;\n}\n\n.igv-viewport-content {\n position: relative;\n width: 100%;\n}\n.igv-viewport-content > canvas {\n position: relative;\n display: block;\n}\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%;\n}\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453;\n}\n\n.igv-axis-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px;\n}\n.igv-axis-column > div {\n position: relative;\n margin-top: 5px;\n width: 100%;\n}\n.igv-axis-column > div > div {\n z-index: 512;\n position: absolute;\n top: 8px;\n left: 8px;\n width: fit-content;\n height: fit-content;\n background-color: transparent;\n display: grid;\n align-items: start;\n justify-items: center;\n}\n.igv-axis-column > div > div > input {\n display: block;\n margin: unset;\n cursor: pointer;\n}\n\n.igv-column {\n position: relative;\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-sample-info-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-sample-name-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-scrollbar-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px;\n}\n.igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px;\n}\n.igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4;\n}\n\n.igv-track-drag-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white;\n}\n.igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.igv-track-drag-column .igv-track-drag-handle-color {\n background-color: #c4c4c4;\n}\n.igv-track-drag-column .igv-track-drag-handle-hover-color {\n background-color: #787878;\n}\n.igv-track-drag-column .igv-track-drag-handle-selected-color {\n background-color: #0963fa;\n}\n.igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n}\n\n.igv-gear-menu-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px;\n}\n.igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white;\n}\n.igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F;\n}\n.igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444;\n}\n\n/*# sourceMappingURL=igv.css.map */\n';
|
|
73734
73740
|
|
|
73735
73741
|
/**
|
|
73736
73742
|
* Manages XQTL selections.
|
|
@@ -74613,6 +74619,10 @@ class Browser {
|
|
|
74613
74619
|
*/
|
|
74614
74620
|
async loadGenome(idOrConfig) {
|
|
74615
74621
|
|
|
74622
|
+
if(idOrConfig.genarkAccession) {
|
|
74623
|
+
idOrConfig.url = convertToHubURL(idOrConfig.genarkAccession);
|
|
74624
|
+
}
|
|
74625
|
+
|
|
74616
74626
|
// Translate the generic "url" field, used by clients such as igv-webapp
|
|
74617
74627
|
if (idOrConfig.url) {
|
|
74618
74628
|
if (isString$2(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt")) {
|