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